├── .DS_Store
├── .editorconfig
├── .github
├── maven-cd-settings.xml
├── maven-ci-settings.xml
└── workflows
│ ├── ci-4.x.yml
│ ├── ci-5.x-stable.yml
│ ├── ci-5.x.yml
│ ├── ci-matrix-5.x.yml
│ ├── ci.yml
│ └── deploy.yml
├── .gitignore
├── LICENSE
├── README.adoc
├── pom.xml
└── src
├── main
├── asciidoc
│ ├── index.adoc
│ └── override
│ │ └── rxjava2.adoc
├── generated
│ └── io
│ │ └── vertx
│ │ └── cassandra
│ │ └── CassandraClientOptionsConverter.java
└── java
│ ├── examples
│ ├── CassandraClientExamples.java
│ └── package-info.java
│ ├── io
│ └── vertx
│ │ └── cassandra
│ │ ├── CassandraClient.java
│ │ ├── CassandraClientOptions.java
│ │ ├── CassandraRowStream.java
│ │ ├── ResultSet.java
│ │ ├── impl
│ │ ├── CassandraClientImpl.java
│ │ ├── CassandraRowStreamImpl.java
│ │ ├── ResultSetImpl.java
│ │ ├── SessionHolder.java
│ │ └── tracing
│ │ │ ├── QueryRequest.java
│ │ │ └── RequestTags.java
│ │ └── package-info.java
│ └── module-info.java
└── test
├── java
└── io
│ └── vertx
│ └── cassandra
│ └── tests
│ ├── AuthenticationTest.java
│ ├── CassandraClientTestBase.java
│ ├── CloseHookTest.java
│ ├── ExecutionTest.java
│ ├── SharedTest.java
│ ├── StreamingTest.java
│ ├── ThreadingCheckTest.java
│ ├── TracingTest.java
│ ├── VerticleWithCassandraClient.java
│ └── impl
│ └── SessionHolderMapCleaningTest.java
└── resources
├── auth-container
└── Dockerfile
└── logback.xml
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vert-x3/vertx-cassandra-client/aa67874bd59a4f8e328ffaa1098b0ab4e85c28b4/.DS_Store
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | trim_trailing_whitespace = true
8 | end_of_line = lf
9 | insert_final_newline = true
--------------------------------------------------------------------------------
/.github/maven-cd-settings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | false
20 |
21 |
22 |
23 | vertx-snapshots-repository
24 | ${env.VERTX_NEXUS_USERNAME}
25 | ${env.VERTX_NEXUS_PASSWORD}
26 |
27 |
28 |
29 |
30 |
31 | google-mirror
32 |
33 | true
34 |
35 |
36 |
37 | google-maven-central
38 | GCS Maven Central mirror EU
39 | https://maven-central.storage-download.googleapis.com/maven2/
40 |
41 | true
42 |
43 |
44 | false
45 |
46 |
47 |
48 |
49 |
50 | google-maven-central
51 | GCS Maven Central mirror
52 | https://maven-central.storage-download.googleapis.com/maven2/
53 |
54 | true
55 |
56 |
57 | false
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/.github/maven-ci-settings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | false
20 |
21 |
22 |
23 | google-mirror
24 |
25 | true
26 |
27 |
28 |
29 | google-maven-central
30 | GCS Maven Central mirror EU
31 | https://maven-central.storage-download.googleapis.com/maven2/
32 |
33 | true
34 |
35 |
36 | false
37 |
38 |
39 |
40 |
41 |
42 | google-maven-central
43 | GCS Maven Central mirror
44 | https://maven-central.storage-download.googleapis.com/maven2/
45 |
46 | true
47 |
48 |
49 | false
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/.github/workflows/ci-4.x.yml:
--------------------------------------------------------------------------------
1 | name: vertx-cassandra-client (4.x)
2 | on:
3 | schedule:
4 | - cron: '0 4 * * *'
5 | jobs:
6 | CI:
7 | strategy:
8 | matrix:
9 | include:
10 | - os: ubuntu-latest
11 | jdk: 8
12 | - os: ubuntu-latest
13 | jdk: 17
14 | uses: ./.github/workflows/ci.yml
15 | with:
16 | branch: 4.x
17 | jdk: ${{ matrix.jdk }}
18 | os: ${{ matrix.os }}
19 | secrets: inherit
20 | Deploy:
21 | if: ${{ github.repository_owner == 'vert-x3' && (github.event_name == 'push' || github.event_name == 'schedule') }}
22 | needs: CI
23 | uses: ./.github/workflows/deploy.yml
24 | with:
25 | branch: 4.x
26 | jdk: 8
27 | secrets: inherit
28 |
--------------------------------------------------------------------------------
/.github/workflows/ci-5.x-stable.yml:
--------------------------------------------------------------------------------
1 | name: vertx-cassandra-client (5.x-stable)
2 | on:
3 | push:
4 | branches:
5 | - '5.[0-9]+'
6 | pull_request:
7 | branches:
8 | - '5.[0-9]+'
9 | schedule:
10 | - cron: '0 6 * * *'
11 | jobs:
12 | CI-CD:
13 | uses: ./.github/workflows/ci-matrix-5.x.yml
14 | secrets: inherit
15 | with:
16 | branch: ${{ github.event_name == 'schedule' && vars.VERTX_5_STABLE_BRANCH || github.event.pull_request.head.sha || github.ref_name }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci-5.x.yml:
--------------------------------------------------------------------------------
1 | name: vertx-cassandra-client (5.x)
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - master
9 | schedule:
10 | - cron: '0 5 * * *'
11 | jobs:
12 | CI-CD:
13 | uses: ./.github/workflows/ci-matrix-5.x.yml
14 | secrets: inherit
15 | with:
16 | branch: ${{ github.event.pull_request.head.sha || github.ref_name }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci-matrix-5.x.yml:
--------------------------------------------------------------------------------
1 | name: CI matrix (5.x)
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jobs:
9 | CI:
10 | strategy:
11 | matrix:
12 | include:
13 | - os: ubuntu-latest
14 | jdk: 11
15 | - os: ubuntu-latest
16 | jdk: 21
17 | uses: ./.github/workflows/ci.yml
18 | with:
19 | branch: ${{ inputs.branch }}
20 | jdk: ${{ matrix.jdk }}
21 | os: ${{ matrix.os }}
22 | secrets: inherit
23 | Deploy:
24 | if: ${{ github.repository_owner == 'vert-x3' && (github.event_name == 'push' || github.event_name == 'schedule') }}
25 | needs: CI
26 | uses: ./.github/workflows/deploy.yml
27 | with:
28 | branch: ${{ inputs.branch }}
29 | jdk: 11
30 | secrets: inherit
31 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jdk:
9 | default: 8
10 | type: string
11 | os:
12 | default: ubuntu-latest
13 | type: string
14 | jobs:
15 | Test:
16 | name: Run tests
17 | runs-on: ${{ inputs.os }}
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | ref: ${{ inputs.branch }}
23 | - name: Install JDK
24 | uses: actions/setup-java@v2
25 | with:
26 | java-version: ${{ inputs.jdk }}
27 | distribution: temurin
28 | - name: Run tests
29 | run: mvn -s .github/maven-ci-settings.xml -q clean verify -B
30 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jdk:
9 | default: 8
10 | type: string
11 | jobs:
12 | Deploy:
13 | name: Deploy to OSSRH
14 | runs-on: ubuntu-latest
15 | env:
16 | VERTX_NEXUS_USERNAME: ${{ secrets.VERTX_NEXUS_USERNAME }}
17 | VERTX_NEXUS_PASSWORD: ${{ secrets.VERTX_NEXUS_PASSWORD }}
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | ref: ${{ inputs.branch }}
23 | - name: Install JDK
24 | uses: actions/setup-java@v2
25 | with:
26 | java-version: ${{ inputs.jdk }}
27 | distribution: temurin
28 | - name: Get project version
29 | run: echo "PROJECT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -q -DforceStdout | grep -v '\[')" >> $GITHUB_ENV
30 | - name: Maven deploy
31 | if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
32 | run: mvn deploy -s .github/maven-cd-settings.xml -DskipTests -B
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/maven,vertx,eclipse,intellij,intellij+all,intellij+iml
3 |
4 | ### Eclipse ###
5 |
6 | .metadata
7 | bin/
8 | tmp/
9 | *.tmp
10 | *.bak
11 | *.swp
12 | *~.nib
13 | local.properties
14 | .settings/
15 | .loadpath
16 | .recommenders
17 |
18 | # External tool builders
19 | .externalToolBuilders/
20 |
21 | # Locally stored "Eclipse launch configurations"
22 | *.launch
23 |
24 | # PyDev specific (Python IDE for Eclipse)
25 | *.pydevproject
26 |
27 | # CDT-specific (C/C++ Development Tooling)
28 | .cproject
29 |
30 | # Java annotation processor (APT)
31 | .factorypath
32 |
33 | # PDT-specific (PHP Development Tools)
34 | .buildpath
35 |
36 | # sbteclipse plugin
37 | .target
38 |
39 | # Tern plugin
40 | .tern-project
41 |
42 | # TeXlipse plugin
43 | .texlipse
44 |
45 | # STS (Spring Tool Suite)
46 | .springBeans
47 |
48 | # Code Recommenders
49 | .recommenders/
50 |
51 | # Scala IDE specific (Scala & Java development for Eclipse)
52 | .cache-main
53 | .scala_dependencies
54 | .worksheet
55 |
56 | ### Eclipse Patch ###
57 | # Eclipse Core
58 | .project
59 |
60 | # JDT-specific (Eclipse Java Development Tools)
61 | .classpath
62 |
63 | # Annotation Processing
64 | .apt_generated
65 |
66 | ### Intellij ###
67 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
68 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
69 |
70 | # User-specific stuff:
71 | .idea/**/workspace.xml
72 | .idea/**/tasks.xml
73 | .idea/dictionaries
74 |
75 | # Sensitive or high-churn files:
76 | .idea/**/dataSources/
77 | .idea/**/dataSources.ids
78 | .idea/**/dataSources.xml
79 | .idea/**/dataSources.local.xml
80 | .idea/**/sqlDataSources.xml
81 | .idea/**/dynamic.xml
82 | .idea/**/uiDesigner.xml
83 |
84 | # Gradle:
85 | .idea/**/gradle.xml
86 | .idea/**/libraries
87 |
88 | # CMake
89 | cmake-build-debug/
90 |
91 | # Mongo Explorer plugin:
92 | .idea/**/mongoSettings.xml
93 |
94 | ## File-based project format:
95 | *.iws
96 |
97 | ## Plugin-specific files:
98 |
99 | # IntelliJ
100 | /out/
101 |
102 | # mpeltonen/sbt-idea plugin
103 | .idea_modules/
104 |
105 | # JIRA plugin
106 | atlassian-ide-plugin.xml
107 |
108 | # Cursive Clojure plugin
109 | .idea/replstate.xml
110 |
111 | # Ruby plugin and RubyMine
112 | /.rakeTasks
113 |
114 | # Crashlytics plugin (for Android Studio and IntelliJ)
115 | com_crashlytics_export_strings.xml
116 | crashlytics.properties
117 | crashlytics-build.properties
118 | fabric.properties
119 |
120 | ### Intellij Patch ###
121 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
122 |
123 | # *.iml
124 | # modules.xml
125 | # .idea/misc.xml
126 | # *.ipr
127 |
128 | # Sonarlint plugin
129 | .idea/sonarlint
130 |
131 | ### Intellij+all ###
132 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
133 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
134 |
135 | # User-specific stuff:
136 |
137 | # Sensitive or high-churn files:
138 |
139 | # Gradle:
140 |
141 | # CMake
142 |
143 | # Mongo Explorer plugin:
144 |
145 | ## File-based project format:
146 |
147 | ## Plugin-specific files:
148 |
149 | # IntelliJ
150 |
151 | # mpeltonen/sbt-idea plugin
152 |
153 | # JIRA plugin
154 |
155 | # Cursive Clojure plugin
156 |
157 | # Ruby plugin and RubyMine
158 |
159 | # Crashlytics plugin (for Android Studio and IntelliJ)
160 |
161 | ### Intellij+all Patch ###
162 | # Ignores the whole .idea folder and all .iml files
163 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
164 |
165 | .idea/
166 |
167 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
168 |
169 | *.iml
170 | modules.xml
171 | .idea/misc.xml
172 | *.ipr
173 |
174 | ### Intellij+iml ###
175 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
176 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
177 |
178 | # User-specific stuff:
179 |
180 | # Sensitive or high-churn files:
181 |
182 | # Gradle:
183 |
184 | # CMake
185 |
186 | # Mongo Explorer plugin:
187 |
188 | ## File-based project format:
189 |
190 | ## Plugin-specific files:
191 |
192 | # IntelliJ
193 |
194 | # mpeltonen/sbt-idea plugin
195 |
196 | # JIRA plugin
197 |
198 | # Cursive Clojure plugin
199 |
200 | # Ruby plugin and RubyMine
201 |
202 | # Crashlytics plugin (for Android Studio and IntelliJ)
203 |
204 | ### Intellij+iml Patch ###
205 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
206 |
207 |
208 | ### Maven ###
209 | target/
210 | pom.xml.tag
211 | pom.xml.releaseBackup
212 | pom.xml.versionsBackup
213 | pom.xml.next
214 | release.properties
215 | dependency-reduced-pom.xml
216 | buildNumber.properties
217 | .mvn/timing.properties
218 |
219 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
220 | !/.mvn/wrapper/maven-wrapper.jar
221 |
222 | ### Vertx ###
223 | # Vertx cache directory
224 | .vertx
225 |
226 | # End of https://www.gitignore.io/api/maven,vertx,eclipse,intellij,intellij+all,intellij+iml
227 | .vscode/
228 | src/main/kotlin
229 | src/main/scala
230 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2018 The Vert.x Community
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = Vert.x Cassandra client
2 |
3 | image:https://github.com/vert-x3/vertx-cassandra-client/actions/workflows/ci-5.x.yml/badge.svg["Build Status (5.x)",link="https://github.com/vert-x3/vertx-cassandra-client/actions/workflows/ci-5.x.yml"]
4 | image:https://github.com/vert-x3/vertx-cassandra-client/actions/workflows/ci-4.x.yml/badge.svg["Build Status (4.x)",link="https://github.com/vert-x3/vertx-cassandra-client/actions/workflows/ci-4.x.yml"]
5 |
6 | The Vert.x Cassandra client is an extension for interacting with http://cassandra.apache.org/[Apache Cassandra].
7 |
8 | The client is built on top of https://github.com/datastax/java-driver[DataStax Java Driver].
9 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | io.vertx
7 | vertx5-parent
8 | 12
9 |
10 |
11 | vertx-cassandra-client
12 | 5.1.0-SNAPSHOT
13 |
14 |
15 | scm:git:git@github.com:vert-x3/vertx-cassandra-client.git
16 | scm:git:git@github.com:vert-x3/vertx-cassandra-client.git
17 | git@github.com:vert-x3/vertx-cassandra-client.git
18 |
19 |
20 |
21 |
24 | 4.15.0
25 | 4.13.1
26 | 1.20.1
27 | 1.3.12
28 |
29 | false
30 |
31 |
32 |
33 |
34 |
35 | io.vertx
36 | vertx-dependencies
37 | ${project.version}
38 | pom
39 | import
40 |
41 |
42 |
43 |
44 |
45 |
46 | The Apache License, Version 2.0
47 | http://www.apache.org/licenses/LICENSE-2.0.txt
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | com.datastax.oss
56 | java-driver-core
57 | ${datastax-driver.version}
58 |
59 |
60 | org.hdrhistogram
61 | HdrHistogram
62 |
63 |
64 | com.typesafe
65 | config
66 |
67 |
68 |
69 |
70 | org.hdrhistogram
71 | HdrHistogram
72 | 2.1.12
73 |
74 |
75 | com.typesafe
76 | config
77 | 1.4.3
78 |
79 |
80 | com.datastax.oss
81 | java-driver-mapper-runtime
82 | ${datastax-driver.version}
83 | true
84 |
85 |
86 | com.datastax.oss
87 | java-driver-query-builder
88 | ${datastax-driver.version}
89 | true
90 |
91 |
92 |
93 |
94 | io.vertx
95 | vertx-core
96 |
97 |
98 | io.vertx
99 | vertx-codegen-api
100 | true
101 |
102 |
103 | io.vertx
104 | vertx-codegen-json
105 | true
106 |
107 |
108 | io.vertx
109 | vertx-docgen-api
110 | true
111 |
112 |
113 |
114 |
115 | org.slf4j
116 | slf4j-api
117 |
118 |
119 |
120 |
121 | org.testcontainers
122 | testcontainers
123 | ${testcontainers.version}
124 | test
125 |
126 |
127 | org.testcontainers
128 | cassandra
129 | ${testcontainers.version}
130 | test
131 |
132 |
133 | com.datastax.cassandra
134 | cassandra-driver-core
135 |
136 |
137 |
138 |
139 | io.vertx
140 | vertx-unit
141 | ${project.version}
142 | test
143 |
144 |
145 | junit
146 | junit
147 | ${junit.version}
148 | test
149 |
150 |
151 | ch.qos.logback
152 | logback-classic
153 | ${logback.version}
154 | test
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-compiler-plugin
163 |
164 |
165 | default-compile
166 |
167 |
168 |
169 | io.vertx
170 | vertx-codegen
171 | processor
172 |
173 |
174 | io.vertx
175 | vertx-docgen-processor
176 | processor
177 |
178 |
179 |
180 |
181 |
182 | default-testCompile
183 |
184 | false
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | maven-assembly-plugin
194 |
195 |
196 | package-docs
197 |
198 | single
199 |
200 |
201 |
202 |
203 |
204 |
205 |
--------------------------------------------------------------------------------
/src/main/asciidoc/index.adoc:
--------------------------------------------------------------------------------
1 | = Cassandra Client for Vert.x
2 |
3 | A Vert.x client allowing applications to interact with an http://cassandra.apache.org/[Apache Cassandra] service.
4 |
5 | == Getting started
6 |
7 | To use this module, add the following to the _dependencies_ section of your Maven POM file:
8 |
9 | [source,xml,subs="+attributes"]
10 | ----
11 |
12 | io.vertx
13 | vertx-cassandra-client
14 | ${maven.version}
15 |
16 | ----
17 |
18 | Or, if you use Gradle:
19 |
20 | [source,groovy,subs="+attributes"]
21 | ----
22 | compile 'io.vertx:vertx-cassandra-client:${maven.version}'
23 | ----
24 |
25 | == Creating a client
26 |
27 | === Client options
28 |
29 | Cassandra is a distributed system, and it can have many nodes.
30 | To connect to Cassandra you need to specify the addresses of some cluster nodes when creating a {@link io.vertx.cassandra.CassandraClientOptions} object:
31 |
32 | [source,$lang]
33 | ----
34 | {@link examples.CassandraClientExamples#specifyingNodes}
35 | ----
36 |
37 | By default, the Cassandra client for Vert.x connects to the local machine's port `9042` and is not tied to any specific keyspace.
38 | But you can set either or both of these options:
39 |
40 | [source,$lang]
41 | ----
42 | {@link examples.CassandraClientExamples#portAndKeyspace}
43 | ----
44 |
45 | TIP: For fine tuning purposes, {@link io.vertx.cassandra.CassandraClientOptions} exposes a `com.datastax.driver.core.Cluster.Builder` instance.
46 |
47 | === Shared clients
48 |
49 | If you deploy multiple instances of your verticle or have different verticles interacting with the same database, it is recommended to create a shared client:
50 |
51 | [source,$lang]
52 | ----
53 | {@link examples.CassandraClientExamples#sharedClient}
54 | ----
55 |
56 | Shared clients with the same name will use a single underlying `com.datastax.driver.core.Session`.
57 |
58 | === Client lifecycle
59 |
60 | After the client is created, it is not connected until the first query is executed.
61 |
62 | TIP: A shared client can be connected after creation if another client with the same name has already executed a query.
63 |
64 | Clients created inside a verticle are automatically stopped when the verticle is undeployed.
65 | In other words, you do not need to invoke {@link io.vertx.cassandra.CassandraClient#close} in the verticle `stop` method.
66 |
67 | In all other cases, you must manually close the client.
68 |
69 | NOTE: When a shared client is closed, the driver dession is not closed if other clients with the same name are still running.
70 |
71 | == Using the API
72 |
73 | The client API is represented by {@link io.vertx.cassandra.CassandraClient}.
74 |
75 | === Querying
76 |
77 | You can get query results using three different ways.
78 |
79 | ==== Streaming
80 |
81 | The streaming API is most appropriate when you need to consume results iteratively, e.g you want to process each item.
82 | This is very efficient specially for large amount of rows.
83 |
84 | In order to give you some inspiration and ideas on how you can use the API, we'd like to you to consider this example:
85 |
86 | [source,$lang]
87 | ----
88 | {@link examples.CassandraClientExamples#streamingViaHttp}
89 | ----
90 |
91 | In the example, we are executing a query, and stream results via HTTP.
92 |
93 | ==== Bulk fetching
94 |
95 | This API should be used when you need to process all the rows at the same time.
96 |
97 | [source,$lang]
98 | ----
99 | {@link examples.CassandraClientExamples#fetchAll}
100 | ----
101 |
102 | CAUTION: Use bulk fetching only if you can afford to load the full result set in memory.
103 |
104 | === Collector queries
105 |
106 | You can use Java collectors with the query API:
107 |
108 | [source,$lang]
109 | ----
110 | {@link examples.CassandraClientExamples#executeAndCollect}
111 | ----
112 |
113 | ==== Low level fetch
114 |
115 | This API provides greater control over loading at the expense of being a bit lower-level than the streaming and bulk fetching APIs.
116 |
117 | [source,$lang]
118 | ----
119 | {@link examples.CassandraClientExamples#lowLevelQuerying}
120 | ----
121 |
122 | === Prepared queries
123 |
124 | For security and efficiency reasons, it is a good idea to use prepared statements for all the queries you are using more than once.
125 |
126 | You can prepare a query:
127 |
128 | [source,$lang]
129 | ----
130 | {@link examples.CassandraClientExamples#prepareQuery}
131 | ----
132 |
133 | And then use the https://docs.datastax.com/en/drivers/java/${datastax.driver.minor.version}/com/datastax/driver/core/PreparedStatement.html[`PreparedStatement`] for all the next queries:
134 |
135 | [source,$lang]
136 | ----
137 | {@link examples.CassandraClientExamples#usingPreparedStatementFuture}
138 | ----
139 |
140 | === Batching
141 |
142 | In case you'd like to execute several queries at once, you can use https://docs.datastax.com/en/drivers/java/${datastax.driver.minor.version}/com/datastax/driver/core/BatchStatement.html[`BatchStatement`] for that:
143 |
144 | [source,$lang]
145 | ----
146 | {@link examples.CassandraClientExamples#batching}
147 | ----
148 |
149 | == Tracing queries
150 |
151 | The Cassandra Client can trace query execution when Vert.x has tracing enabled.
152 |
153 | The client reports the following _client_ spans:
154 |
155 | * `Query` operation name
156 | * tags
157 | ** `peer.address`: list of nodes known to the driver, in the form `[127_0_0_1:9042,localhost:9042,myhost_mydomain:9042]`
158 | ** `span.kind`: `client`
159 | ** `db.instance`: the keyspace
160 | ** `db.statement`: the CQL query
161 | ** `db.type`: `cassandra`
162 |
163 | The default tracing policy is {@link io.vertx.core.tracing.TracingPolicy#PROPAGATE}, the client will only create a span when involved in an active trace.
164 |
165 | You can change the client policy with {@link io.vertx.cassandra.CassandraClientOptions#setTracingPolicy}.
166 | For example, you can set {@link io.vertx.core.tracing.TracingPolicy#ALWAYS} to always report a span:
167 |
168 | [source,$lang]
169 | ----
170 | {@link examples.CassandraClientExamples#tracing}
171 | ----
172 |
--------------------------------------------------------------------------------
/src/main/asciidoc/override/rxjava2.adoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vert-x3/vertx-cassandra-client/aa67874bd59a4f8e328ffaa1098b0ab4e85c28b4/src/main/asciidoc/override/rxjava2.adoc
--------------------------------------------------------------------------------
/src/main/generated/io/vertx/cassandra/CassandraClientOptionsConverter.java:
--------------------------------------------------------------------------------
1 | package io.vertx.cassandra;
2 |
3 | import io.vertx.core.json.JsonObject;
4 | import io.vertx.core.json.JsonArray;
5 | import java.time.Instant;
6 | import java.time.format.DateTimeFormatter;
7 |
8 | /**
9 | * Converter and mapper for {@link io.vertx.cassandra.CassandraClientOptions}.
10 | * NOTE: This class has been automatically generated from the {@link io.vertx.cassandra.CassandraClientOptions} original class using Vert.x codegen.
11 | */
12 | public class CassandraClientOptionsConverter {
13 |
14 | static void fromJson(Iterable> json, CassandraClientOptions obj) {
15 | for (java.util.Map.Entry member : json) {
16 | switch (member.getKey()) {
17 | case "contactPoints":
18 | if (member.getValue() instanceof JsonObject) {
19 | ((Iterable>)member.getValue()).forEach(entry -> {
20 | if (entry.getValue() instanceof Number)
21 | obj.addContactPoint(entry.getKey(), ((Number)entry.getValue()).intValue());
22 | });
23 | }
24 | break;
25 | case "keyspace":
26 | if (member.getValue() instanceof String) {
27 | obj.setKeyspace((String)member.getValue());
28 | }
29 | break;
30 | case "username":
31 | if (member.getValue() instanceof String) {
32 | obj.setUsername((String)member.getValue());
33 | }
34 | break;
35 | case "password":
36 | if (member.getValue() instanceof String) {
37 | obj.setPassword((String)member.getValue());
38 | }
39 | break;
40 | case "tracingPolicy":
41 | if (member.getValue() instanceof String) {
42 | obj.setTracingPolicy(io.vertx.core.tracing.TracingPolicy.valueOf((String)member.getValue()));
43 | }
44 | break;
45 | }
46 | }
47 | }
48 |
49 | static void toJson(CassandraClientOptions obj, JsonObject json) {
50 | toJson(obj, json.getMap());
51 | }
52 |
53 | static void toJson(CassandraClientOptions obj, java.util.Map json) {
54 | if (obj.getKeyspace() != null) {
55 | json.put("keyspace", obj.getKeyspace());
56 | }
57 | if (obj.getUsername() != null) {
58 | json.put("username", obj.getUsername());
59 | }
60 | if (obj.getPassword() != null) {
61 | json.put("password", obj.getPassword());
62 | }
63 | if (obj.getTracingPolicy() != null) {
64 | json.put("tracingPolicy", obj.getTracingPolicy().name());
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/examples/CassandraClientExamples.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package examples;
17 |
18 | import com.datastax.oss.driver.api.core.cql.*;
19 | import io.vertx.cassandra.CassandraClient;
20 | import io.vertx.cassandra.CassandraClientOptions;
21 | import io.vertx.cassandra.CassandraRowStream;
22 | import io.vertx.cassandra.ResultSet;
23 | import io.vertx.core.Vertx;
24 | import io.vertx.core.http.HttpServerResponse;
25 | import io.vertx.core.tracing.TracingPolicy;
26 |
27 | import java.util.List;
28 | import java.util.stream.Collector;
29 |
30 | public class CassandraClientExamples {
31 |
32 | public void specifyingNodes(Vertx vertx) {
33 | CassandraClientOptions options = new CassandraClientOptions()
34 | .addContactPoint("node1.address", 9142)
35 | .addContactPoint("node2.address", 9142)
36 | .addContactPoint("node3.address", 9142);
37 | CassandraClient client = CassandraClient.create(vertx, options);
38 | }
39 |
40 | public void portAndKeyspace(Vertx vertx) {
41 | CassandraClientOptions options = new CassandraClientOptions()
42 | .addContactPoint("localhost", 9142)
43 | .setKeyspace("my_keyspace");
44 | CassandraClient client = CassandraClient.create(vertx, options);
45 | }
46 |
47 | public void sharedClient(Vertx vertx) {
48 | CassandraClientOptions options = new CassandraClientOptions()
49 | .addContactPoint("node1.address", 9142)
50 | .addContactPoint("node2.address", 9142)
51 | .addContactPoint("node3.address", 9142)
52 | .setKeyspace("my_keyspace");
53 | CassandraClient client = CassandraClient.createShared(vertx, "sharedClientName", options);
54 | }
55 |
56 | public void lowLevelQuerying(CassandraClient cassandraClient) {
57 | cassandraClient.execute("SELECT * FROM my_keyspace.my_table where my_key = 'my_value'")
58 | .onComplete(execute -> {
59 | if (execute.succeeded()) {
60 | ResultSet resultSet = execute.result();
61 |
62 | if (resultSet.remaining() != 0) {
63 | Row row = resultSet.one();
64 | System.out.println("One row successfully fetched");
65 | } else if (!resultSet.hasMorePages()) {
66 | System.out.println("No pages to fetch");
67 | } else {
68 | resultSet.fetchNextPage().onComplete(fetchMoreResults -> {
69 | if (fetchMoreResults.succeeded()) {
70 | int availableWithoutFetching = resultSet.remaining();
71 | System.out.println("Now we have " + availableWithoutFetching + " rows fetched, but not consumed!");
72 | } else {
73 | System.out.println("Unable to fetch more results");
74 | fetchMoreResults.cause().printStackTrace();
75 | }
76 | });
77 | }
78 | } else {
79 | System.out.println("Unable to execute the query");
80 | execute.cause().printStackTrace();
81 | }
82 | });
83 | }
84 |
85 | public void executeAndCollect(CassandraClient cassandraClient, Collector listCollector) {
86 | // Run the query with the collector
87 | cassandraClient.execute("SELECT * FROM users", listCollector)
88 | .onComplete(ar -> {
89 | if (ar.succeeded()) {
90 | // Get the string created by the collector
91 | String list = ar.result();
92 | System.out.println("Got " + list);
93 | } else {
94 | System.out.println("Failure: " + ar.cause().getMessage());
95 | }
96 | });
97 | }
98 |
99 | public void streamingViaHttp(Vertx vertx, CassandraClient cassandraClient, HttpServerResponse response) {
100 | cassandraClient.queryStream("SELECT my_string_col FROM my_keyspace.my_table where my_key = 'my_value'")
101 | .onComplete(queryStream -> {
102 | if (queryStream.succeeded()) {
103 | CassandraRowStream stream = queryStream.result();
104 |
105 | // resume stream when queue is ready to accept buffers again
106 | response.drainHandler(v -> stream.resume());
107 |
108 | stream.handler(row -> {
109 | String value = row.getString("my_string_col");
110 | response.write(value);
111 |
112 | // pause row stream when we buffer queue is full
113 | if (response.writeQueueFull()) {
114 | stream.pause();
115 | }
116 | });
117 |
118 | // end request when we reached end of the stream
119 | stream.endHandler(end -> response.end());
120 |
121 | } else {
122 | queryStream.cause().printStackTrace();
123 | // response with internal server error if we are not able to execute given query
124 | response
125 | .setStatusCode(500)
126 | .end("Unable to execute the query");
127 | }
128 | });
129 | }
130 |
131 | public void fetchAll(CassandraClient cassandraClient) {
132 | cassandraClient.executeWithFullFetch("SELECT * FROM my_keyspace.my_table where my_key = 'my_value'")
133 | .onComplete(executeWithFullFetch -> {
134 | if (executeWithFullFetch.succeeded()) {
135 | List rows = executeWithFullFetch.result();
136 | for (Row row : rows) {
137 | // handle each row here
138 | }
139 | } else {
140 | System.out.println("Unable to execute the query");
141 | executeWithFullFetch.cause().printStackTrace();
142 | }
143 | });
144 | }
145 |
146 | public void prepareQuery(CassandraClient cassandraClient) {
147 | cassandraClient.prepare("SELECT * FROM my_keyspace.my_table where my_key = ? ")
148 | .onComplete(preparedStatementResult -> {
149 | if (preparedStatementResult.succeeded()) {
150 | System.out.println("The query has successfully been prepared");
151 | PreparedStatement preparedStatement = preparedStatementResult.result();
152 | // now you can use this PreparedStatement object for the next queries
153 | } else {
154 | System.out.println("Unable to prepare the query");
155 | preparedStatementResult.cause().printStackTrace();
156 | }
157 | });
158 | }
159 |
160 | public void usingPreparedStatementFuture(CassandraClient cassandraClient, PreparedStatement preparedStatement) {
161 | // You can execute you prepared statement using any way to execute queries.
162 |
163 | // Low level fetch API
164 | cassandraClient.execute(preparedStatement.bind("my_value"))
165 | .onComplete(done -> {
166 | ResultSet results = done.result();
167 | // handle results here
168 | });
169 |
170 | // Bulk fetching API
171 | cassandraClient.executeWithFullFetch(preparedStatement.bind("my_value"))
172 | .onComplete(done -> {
173 | List results = done.result();
174 | // handle results here
175 | });
176 |
177 | // Streaming API
178 | cassandraClient.queryStream(preparedStatement.bind("my_value"))
179 | .onComplete(done -> {
180 | CassandraRowStream results = done.result();
181 | // handle results here
182 | });
183 | }
184 |
185 | public void batching(CassandraClient cassandraClient) {
186 | BatchStatement batchStatement = BatchStatement.newInstance(BatchType.LOGGED)
187 | .add(SimpleStatement.newInstance("INSERT INTO NAMES (name) VALUES ('Pavel')"))
188 | .add(SimpleStatement.newInstance("INSERT INTO NAMES (name) VALUES ('Thomas')"))
189 | .add(SimpleStatement.newInstance("INSERT INTO NAMES (name) VALUES ('Julien')"));
190 |
191 | cassandraClient
192 | .execute(batchStatement)
193 | .onComplete(result -> {
194 | if (result.succeeded()) {
195 | System.out.println("The given batch executed successfully");
196 | } else {
197 | System.out.println("Unable to execute the batch");
198 | result.cause().printStackTrace();
199 | }
200 | });
201 | }
202 |
203 | public void tracing() {
204 | CassandraClientOptions options = new CassandraClientOptions()
205 | .setTracingPolicy(TracingPolicy.ALWAYS);
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/main/java/examples/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @Source
17 | package examples;
18 |
19 | import io.vertx.docgen.Source;
20 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/CassandraClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra;
17 |
18 | import com.datastax.oss.driver.api.core.cql.PreparedStatement;
19 | import com.datastax.oss.driver.api.core.cql.Row;
20 | import com.datastax.oss.driver.api.core.cql.SimpleStatement;
21 | import com.datastax.oss.driver.api.core.cql.Statement;
22 | import com.datastax.oss.driver.api.core.metadata.Metadata;
23 | import io.vertx.cassandra.impl.CassandraClientImpl;
24 | import io.vertx.codegen.annotations.GenIgnore;
25 | import io.vertx.codegen.annotations.VertxGen;
26 | import io.vertx.core.Future;
27 | import io.vertx.core.Vertx;
28 |
29 | import java.util.List;
30 | import java.util.UUID;
31 | import java.util.stream.Collector;
32 |
33 | /**
34 | * Eclipse Vert.x Cassandra client.
35 | *
36 | * @author Pavel Drankou
37 | * @author Thomas Segismont
38 | */
39 | @VertxGen
40 | public interface CassandraClient {
41 |
42 | /**
43 | * The default shared client name.
44 | */
45 | String DEFAULT_SHARED_CLIENT_NAME = "DEFAULT";
46 |
47 | /**
48 | * Like {@link CassandraClient#create(Vertx, CassandraClientOptions)} with default options.
49 | */
50 | static CassandraClient create(Vertx vertx) {
51 | return create(vertx, new CassandraClientOptions());
52 | }
53 |
54 | /**
55 | * Create a Cassandra client which maintains its own driver session.
56 | *
57 | * It is not recommended to create several non shared clients in an application.
58 | *
59 | * @param vertx the Vert.x instance
60 | * @param options the options
61 | * @return the client
62 | */
63 | static CassandraClient create(Vertx vertx, CassandraClientOptions options) {
64 | return new CassandraClientImpl(vertx, UUID.randomUUID().toString(), options);
65 | }
66 |
67 | /**
68 | * Like {@link CassandraClient#createShared(Vertx, String, CassandraClientOptions)} with default options and client name.
69 | */
70 | static CassandraClient createShared(Vertx vertx) {
71 | return createShared(vertx, DEFAULT_SHARED_CLIENT_NAME);
72 | }
73 |
74 | /**
75 | * Like {@link CassandraClient#createShared(Vertx, String, CassandraClientOptions)} with default options.
76 | */
77 | static CassandraClient createShared(Vertx vertx, String clientName) {
78 | return createShared(vertx, clientName, new CassandraClientOptions());
79 | }
80 |
81 | /**
82 | * Like {@link CassandraClient#createShared(Vertx, String, CassandraClientOptions)} with default client name.
83 | */
84 | static CassandraClient createShared(Vertx vertx, CassandraClientOptions options) {
85 | return createShared(vertx, DEFAULT_SHARED_CLIENT_NAME, options);
86 | }
87 |
88 | /**
89 | * Create a Cassandra client that shares its driver session with any other client having the same name.
90 | *
91 | * @param vertx the Vert.x instance
92 | * @param options the options
93 | * @param clientName the shared client name
94 | * @return the client
95 | */
96 | static CassandraClient createShared(Vertx vertx, String clientName, CassandraClientOptions options) {
97 | return new CassandraClientImpl(vertx, clientName, options);
98 | }
99 |
100 | /**
101 | * @return whether this Cassandra client instance is connected
102 | */
103 | boolean isConnected();
104 |
105 | /**
106 | * Execute the query and provide a handler for consuming results.
107 | *
108 | * @param query the query to execute
109 | * @return a future of the result
110 | */
111 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
112 | Future> executeWithFullFetch(String query);
113 |
114 | /**
115 | * Execute the query and provide a handler for consuming results.
116 | *
117 | * @param statement the statement to execute
118 | * @return a future of the result
119 | */
120 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
121 | Future> executeWithFullFetch(Statement statement);
122 |
123 | /**
124 | * Execute the query and provide a handler for consuming results.
125 | *
126 | * @param query the query to execute
127 | * @return a future of the result
128 | */
129 | Future execute(String query);
130 |
131 | /**
132 | * Execute a query and produce a result by applying a collector to result set rows.
133 | *
134 | * @param query the query to execute
135 | * @param collector the collector to use to produce a result
136 | * @param the result type
137 | * @return a future of the result
138 | */
139 | @GenIgnore
140 | Future execute(String query, Collector collector);
141 |
142 | /**
143 | * Execute the statement and provide a handler for consuming results.
144 | *
145 | * @param statement the statement to execute
146 | * @return a future of the result
147 | */
148 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
149 | Future execute(Statement statement);
150 |
151 | /**
152 | * Execute a statement and produce a result by applying a collector to result set rows.
153 | *
154 | * @param statement the statement to execute
155 | * @param collector the collector to use to produce a result
156 | * @param the result type
157 | * @return a future of the result
158 | */
159 | @GenIgnore
160 | Future execute(Statement statement, Collector collector);
161 |
162 | /**
163 | * Prepares the provided query string.
164 | *
165 | * @param query the query to prepare
166 | * @return a future of the result
167 | */
168 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
169 | Future prepare(String query);
170 |
171 | /**
172 | * Prepares the provided a {@link SimpleStatement}.
173 | *
174 | * @param statement the statement to prepare
175 | * @return a future of the result
176 | */
177 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
178 | Future prepare(SimpleStatement statement);
179 |
180 | /**
181 | * Executes the given SQL SELECT statement which returns the results of the query as a read stream.
182 | *
183 | * @param sql the SQL to execute. For example SELECT * FROM table ....
184 | * @return a future of the result
185 | */
186 | Future queryStream(String sql);
187 |
188 | /**
189 | * Executes the given SQL statement which returns the results of the query as a read stream.
190 | *
191 | * @param statement the statement to execute.
192 | * @return a future of the result
193 | */
194 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
195 | Future queryStream(Statement statement);
196 |
197 | /**
198 | * Closes this client.
199 | *
200 | * @return a future of the result
201 | */
202 | Future close();
203 |
204 | /**
205 | * Get {@link Metadata} for the session.
206 | *
207 | * @return a future of the result
208 | */
209 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
210 | Future metadata();
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/CassandraClientOptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra;
17 |
18 | import com.datastax.oss.driver.api.core.CqlSession;
19 | import com.datastax.oss.driver.api.core.CqlSessionBuilder;
20 | import io.vertx.codegen.annotations.DataObject;
21 | import io.vertx.codegen.json.annotations.JsonGen;
22 | import io.vertx.core.json.JsonObject;
23 | import io.vertx.core.tracing.TracingPolicy;
24 |
25 | import java.net.InetSocketAddress;
26 |
27 | /**
28 | * Eclipse Vert.x Cassandra client options.
29 | *
30 | * @author Pavel Drankou
31 | * @author Thomas Segismont
32 | */
33 | @DataObject
34 | @JsonGen(publicConverter = false)
35 | public class CassandraClientOptions {
36 |
37 | /**
38 | * Default port for connecting with Cassandra service.
39 | */
40 | public static final int DEFAULT_PORT = 9042;
41 |
42 | /**
43 | * Default host for connecting with Cassandra service.
44 | */
45 | public static final String DEFAULT_HOST = "localhost";
46 |
47 | private final CqlSessionBuilder builder;
48 |
49 | private String keyspace;
50 | private String username;
51 | private String password;
52 | private TracingPolicy tracingPolicy;
53 |
54 | /**
55 | * Default constructor.
56 | */
57 | public CassandraClientOptions() {
58 | this(CqlSession.builder());
59 | }
60 |
61 | /**
62 | * Copy constructor.
63 | * @param other The other client to copy from.
64 | */
65 | public CassandraClientOptions(CassandraClientOptions other) {
66 | this(other.dataStaxClusterBuilder());
67 | this.setKeyspace(other.getKeyspace());
68 | tracingPolicy = other.tracingPolicy;
69 | }
70 |
71 | /**
72 | * Constructor using an existing {@link CqlSessionBuilder} instance.
73 | */
74 | public CassandraClientOptions(CqlSessionBuilder builder) {
75 | this.builder = builder;
76 | this.tracingPolicy = TracingPolicy.PROPAGATE;
77 | }
78 |
79 | /**
80 | * Constructor to create options from JSON.
81 | *
82 | * @param json the JSON
83 | */
84 | public CassandraClientOptions(JsonObject json) {
85 | this();
86 | CassandraClientOptionsConverter.fromJson(json, this);
87 | }
88 |
89 | /**
90 | * @return a JSON representation of these options
91 | */
92 | public JsonObject toJson() {
93 | JsonObject json = new JsonObject();
94 | CassandraClientOptionsConverter.toJson(this, json);
95 | return json;
96 | }
97 |
98 | /**
99 | * Adds a contact point to use for the initial connection to the cluster
100 | *
101 | * @param address the address
102 | * @return a reference to this, so the API can be used fluently
103 | */
104 | public CassandraClientOptions addContactPoint(InetSocketAddress address) {
105 | builder.addContactPoint(address);
106 | return this;
107 | }
108 |
109 | /**
110 | * Adds a contact point to use for the initial connection to the cluster
111 | *
112 | * @param host the address
113 | * @param port the port
114 | * @return a reference to this, so the API can be used fluently
115 | */
116 | public CassandraClientOptions addContactPoint(String host, int port) {
117 | builder.addContactPoint(InetSocketAddress.createUnresolved(host, port));
118 | return this;
119 | }
120 |
121 | /**
122 | * @return a cluster builder, which will be used by the client
123 | */
124 | public CqlSessionBuilder dataStaxClusterBuilder() {
125 | return builder;
126 | }
127 |
128 | /**
129 | * @return the keyspace to use when creating the Cassandra session
130 | */
131 | public String getKeyspace() {
132 | return keyspace;
133 | }
134 |
135 | /**
136 | * Set the keyspace to use when creating the Cassandra session. Defaults to {@code null}.
137 | *
138 | * @param keyspace the keyspace to use when creating the Cassandra session
139 | *
140 | * @return a reference to this, so the API can be used fluently
141 | */
142 | public CassandraClientOptions setKeyspace(String keyspace) {
143 | this.keyspace = keyspace;
144 | builder.withKeyspace(keyspace);
145 | return this;
146 | }
147 |
148 | /**
149 | * @return the username if plaintext authentication is used
150 | */
151 | public String getUsername() {
152 | return username;
153 | }
154 |
155 | /**
156 | * Set the username for plaintext authentication. Defaults to {@code null}.
157 | *
158 | * @param username the username for plaintext authentication
159 | * @return a reference to this, so the API can be used fluently
160 | */
161 | public CassandraClientOptions setUsername(String username) {
162 | this.username = username;
163 | setAuth();
164 | return this;
165 | }
166 |
167 | private void setAuth() {
168 | if (username == null || password == null) {
169 | builder.withAuthProvider(null);
170 | } else {
171 | builder.withAuthCredentials(username, password);
172 | }
173 | }
174 |
175 | /**
176 | * @return the password if plaintext authentication is used
177 | */
178 | public String getPassword() {
179 | return password;
180 | }
181 |
182 | /**
183 | * Set the password for plaintext authentication. Defaults to {@code null}.
184 | *
185 | * @param password the username for plaintext authentication
186 | * @return a reference to this, so the API can be used fluently
187 | */
188 | public CassandraClientOptions setPassword(String password) {
189 | this.password = password;
190 | setAuth();
191 | return this;
192 | }
193 |
194 | /**
195 | * @return the tracing policy
196 | */
197 | public TracingPolicy getTracingPolicy() {
198 | return tracingPolicy;
199 | }
200 |
201 | /**
202 | * Set the tracing policy for the client behavior when Vert.x has tracing enabled.
203 | *
204 | * @param tracingPolicy the tracing policy
205 | * @return a reference to this, so the API can be used fluently
206 | */
207 | public CassandraClientOptions setTracingPolicy(TracingPolicy tracingPolicy) {
208 | this.tracingPolicy = tracingPolicy;
209 | return this;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/CassandraRowStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra;
17 |
18 | import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
19 | import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
20 | import com.datastax.oss.driver.api.core.cql.Row;
21 | import io.vertx.codegen.annotations.GenIgnore;
22 | import io.vertx.codegen.annotations.VertxGen;
23 | import io.vertx.core.AsyncResult;
24 | import io.vertx.core.Future;
25 | import io.vertx.core.Handler;
26 | import io.vertx.core.streams.ReadStream;
27 | import io.vertx.core.streams.WriteStream;
28 |
29 | /**
30 | * A {@link ReadStream} for {@link Row} consumption.
31 | *
32 | * @author Pavel Drankou
33 | * @author Thomas Segismont
34 | */
35 | @VertxGen
36 | public interface CassandraRowStream extends ReadStream {
37 |
38 | @Override
39 | CassandraRowStream exceptionHandler(Handler handler);
40 |
41 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
42 | @Override
43 | CassandraRowStream handler(Handler handler);
44 |
45 | @Override
46 | CassandraRowStream pause();
47 |
48 | @Override
49 | CassandraRowStream resume();
50 |
51 | @Override
52 | CassandraRowStream endHandler(Handler handler);
53 |
54 | @Override
55 | CassandraRowStream fetch(long l);
56 |
57 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
58 | @Override
59 | default Future pipeTo(WriteStream dst) {
60 | return ReadStream.super.pipeTo(dst);
61 | }
62 |
63 | /**
64 | * Get the {@link ExecutionInfo} provided by the backing {@link ResultSet} for this stream.
65 | *
66 | * @returns the executionInfo
67 | */
68 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
69 | ExecutionInfo executionInfo();
70 |
71 |
72 | /**
73 | * Get the {@link ColumnDefinitions} provided by the backing {@link ResultSet} for this stream.
74 | *
75 | * @returns the columnDefinitions
76 | */
77 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
78 | ColumnDefinitions columnDefinitions();
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/ResultSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra;
17 |
18 | import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
19 | import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
20 | import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
21 | import com.datastax.oss.driver.api.core.cql.Row;
22 | import io.vertx.codegen.annotations.GenIgnore;
23 | import io.vertx.codegen.annotations.VertxGen;
24 | import io.vertx.core.Future;
25 |
26 | import java.util.List;
27 |
28 | /**
29 | * It is like {@link com.datastax.oss.driver.api.core.cql.AsyncResultSet}, but adapted for Vert.x.
30 | *
31 | * @author Pavel Drankou
32 | * @author Thomas Segismont
33 | */
34 | @VertxGen
35 | public interface ResultSet {
36 |
37 | /**
38 | * The method should not be used concurrently with others like {@link #fetchNextPage()} or {@link #one()}.
39 | * This may lead to unexpected result.
40 | *
41 | * @return a future notified all the rows are fetched
42 | */
43 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
44 | Future> all();
45 |
46 | /**
47 | * @see AsyncResultSet#getColumnDefinitions()
48 | */
49 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
50 | ColumnDefinitions getColumnDefinitions();
51 |
52 | /**
53 | * @see AsyncResultSet#getExecutionInfo()
54 | */
55 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
56 | ExecutionInfo getExecutionInfo();
57 |
58 | /**
59 | * @see AsyncResultSet#remaining()
60 | */
61 | int remaining();
62 |
63 | /**
64 | * @see AsyncResultSet#currentPage()
65 | */
66 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
67 | Iterable currentPage();
68 |
69 | /**
70 | * @see AsyncResultSet#one()
71 | */
72 | @GenIgnore(GenIgnore.PERMITTED_TYPE)
73 | Row one();
74 |
75 | /**
76 | * @see AsyncResultSet#hasMorePages()
77 | */
78 | boolean hasMorePages();
79 |
80 | /**
81 | * @see AsyncResultSet#wasApplied()
82 | */
83 | Future fetchNextPage() throws IllegalStateException;
84 |
85 | /**
86 | * @see AsyncResultSet#wasApplied()
87 | */
88 | boolean wasApplied();
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/impl/CassandraClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra.impl;
17 |
18 | import com.datastax.oss.driver.api.core.CqlSession;
19 | import com.datastax.oss.driver.api.core.CqlSessionBuilder;
20 | import com.datastax.oss.driver.api.core.cql.*;
21 | import com.datastax.oss.driver.api.core.metadata.Metadata;
22 | import com.datastax.oss.driver.api.core.session.Session;
23 | import io.vertx.cassandra.CassandraClient;
24 | import io.vertx.cassandra.CassandraClientOptions;
25 | import io.vertx.cassandra.CassandraRowStream;
26 | import io.vertx.cassandra.ResultSet;
27 | import io.vertx.cassandra.impl.tracing.QueryRequest;
28 | import io.vertx.core.*;
29 | import io.vertx.core.internal.ContextInternal;
30 | import io.vertx.core.internal.VertxInternal;
31 | import io.vertx.core.spi.tracing.SpanKind;
32 | import io.vertx.core.spi.tracing.TagExtractor;
33 | import io.vertx.core.spi.tracing.VertxTracer;
34 |
35 | import java.util.List;
36 | import java.util.Map;
37 | import java.util.Objects;
38 | import java.util.function.BiConsumer;
39 | import java.util.function.Function;
40 | import java.util.stream.Collector;
41 |
42 | import static io.vertx.cassandra.impl.tracing.RequestTags.REQUEST_TAG_EXTRACTOR;
43 |
44 | /**
45 | * @author Pavel Drankou
46 | * @author Thomas Segismont
47 | */
48 | public class CassandraClientImpl implements CassandraClient {
49 |
50 | public static final String HOLDERS_LOCAL_MAP_NAME = "__vertx.cassandraClient.sessionHolders";
51 |
52 | final VertxInternal vertx;
53 | private final VertxTracer tracer;
54 | private final String clientName;
55 | private final CassandraClientOptions options;
56 | private final Map holders;
57 | private final ContextInternal creatingContext;
58 |
59 | private boolean closed;
60 |
61 | public CassandraClientImpl(Vertx vertx, String clientName, CassandraClientOptions options) {
62 | Objects.requireNonNull(vertx, "vertx");
63 | Objects.requireNonNull(clientName, "clientName");
64 | Objects.requireNonNull(options, "options");
65 | this.vertx = (VertxInternal) vertx;
66 | this.tracer = ((VertxInternal) vertx).tracer();
67 | this.clientName = clientName;
68 | this.options = options;
69 | this.creatingContext = ((VertxInternal) vertx).getOrCreateContext();
70 | holders = vertx.sharedData().getLocalMap(HOLDERS_LOCAL_MAP_NAME);
71 | SessionHolder current = holders.compute(clientName, (k, h) -> h == null ? new SessionHolder() : h.increment());
72 | creatingContext.addCloseHook(completion -> CassandraClientImpl.this.close().onComplete(completion));
73 | }
74 |
75 | @Override
76 | public synchronized boolean isConnected() {
77 | if (closed) {
78 | return false;
79 | }
80 | Session s = holders.get(clientName).session;
81 | return s != null && !s.isClosed();
82 | }
83 |
84 | @Override
85 | public Future> executeWithFullFetch(String query) {
86 | return executeWithFullFetch(SimpleStatement.newInstance(query));
87 | }
88 |
89 | @Override
90 | public Future> executeWithFullFetch(Statement statement) {
91 | return execute(statement)
92 | .flatMap(ResultSet::all);
93 | }
94 |
95 | @Override
96 | public Future execute(String query) {
97 | return execute(SimpleStatement.newInstance(query));
98 | }
99 |
100 | @Override
101 | public Future execute(String query, Collector collector) {
102 | return execute(SimpleStatement.newInstance(query), collector);
103 | }
104 |
105 | @Override
106 | public Future execute(Statement statement) {
107 | return executeInternal(statement)
108 | .map(rs -> new ResultSetImpl(rs, vertx));
109 | }
110 |
111 | private Future executeInternal(Statement statement) {
112 | return getSession(vertx.getOrCreateContext())
113 | .flatMap(session -> {
114 | Object payload;
115 | if (tracer != null) {
116 | payload = sendRequest(session, statement);
117 | } else {
118 | payload = null;
119 | }
120 | Future future = Future.fromCompletionStage(session.executeAsync(statement), vertx.getContext());
121 | if (tracer != null) {
122 | future = future.onComplete(ar -> receiveResponse(payload, ar));
123 | }
124 | return future;
125 | });
126 | }
127 |
128 | private Object sendRequest(CqlSession session, Statement statement) {
129 | QueryRequest request = new QueryRequest(session, statement);
130 | return tracer.sendRequest(vertx.getContext(), SpanKind.RPC, options.getTracingPolicy(), request, "Query", (k, v) -> {
131 | }, REQUEST_TAG_EXTRACTOR);
132 | }
133 |
134 | private void receiveResponse(Object payload, AsyncResult asyncResult) {
135 | tracer.receiveResponse(vertx.getContext(), null, payload, asyncResult.cause(), TagExtractor.empty());
136 | }
137 |
138 | @Override
139 | public Future execute(Statement statement, Collector collector) {
140 | return executeAndCollect(statement, collector);
141 | }
142 |
143 | private Future executeAndCollect(Statement statement, Collector collector) {
144 | C container = collector.supplier().get();
145 | BiConsumer accumulator = collector.accumulator();
146 | Function finisher = collector.finisher();
147 | return queryStream(statement)
148 | .flatMap(cassandraRowStream -> {
149 | Promise resultPromise = Promise.promise();
150 | cassandraRowStream.endHandler(end -> {
151 | R result = finisher.apply(container);
152 | resultPromise.complete(result);
153 | });
154 | cassandraRowStream.handler(row -> {
155 | accumulator.accept(container, row);
156 | });
157 | cassandraRowStream.exceptionHandler(resultPromise::fail);
158 | return resultPromise.future();
159 | });
160 | }
161 |
162 | @Override
163 | public Future prepare(String query) {
164 | return getSession(vertx.getOrCreateContext())
165 | .flatMap(session -> Future.fromCompletionStage(session.prepareAsync(query), vertx.getContext()));
166 | }
167 |
168 | @Override
169 | public Future prepare(SimpleStatement statement) {
170 | return getSession(vertx.getOrCreateContext())
171 | .flatMap(session -> Future.fromCompletionStage(session.prepareAsync(statement), vertx.getContext()));
172 | }
173 |
174 | @Override
175 | public Future queryStream(String sql) {
176 | return queryStream(SimpleStatement.newInstance(sql));
177 | }
178 |
179 | @Override
180 | public Future queryStream(Statement statement) {
181 | return executeInternal(statement)
182 | .map(rs -> {
183 | ResultSet resultSet = new ResultSetImpl(rs, vertx);
184 | CassandraRowStreamImpl stream = new CassandraRowStreamImpl(vertx.getContext());
185 | stream.init(resultSet);
186 | return stream;
187 | });
188 | }
189 |
190 | @Override
191 | public Future close() {
192 | ContextInternal context = vertx.getOrCreateContext();
193 | if (raiseCloseFlag()) {
194 | do {
195 | SessionHolder current = holders.get(clientName);
196 | SessionHolder next = current.decrement();
197 | if (next.refCount == 0) {
198 | if (holders.remove(clientName, current)) {
199 | if (current.session != null) {
200 | return Future.fromCompletionStage(current.session.closeAsync(), context);
201 | }
202 | break;
203 | }
204 | } else if (holders.replace(clientName, current, next)) {
205 | break;
206 | }
207 | } while (true);
208 | }
209 | return context.succeededFuture();
210 | }
211 |
212 | @Override
213 | public Future metadata() {
214 | return getSession(vertx.getOrCreateContext()).map(Session::getMetadata);
215 | }
216 |
217 | private synchronized boolean raiseCloseFlag() {
218 | if (!closed) {
219 | closed = true;
220 | return true;
221 | }
222 | return false;
223 | }
224 |
225 | synchronized Future getSession(ContextInternal context) {
226 | if (closed) {
227 | return context.failedFuture("Client is closed");
228 | }
229 | SessionHolder holder = holders.get(clientName);
230 | if (holder.session != null) {
231 | return context.succeededFuture(holder.session);
232 | }
233 | return context.executeBlocking(this::connect);
234 | }
235 |
236 | private CqlSession connect() {
237 | SessionHolder current = holders.get(clientName);
238 | if (current == null) {
239 | throw new VertxException("Client closed while connecting", true);
240 | }
241 | if (current.session != null) {
242 | return current.session;
243 | }
244 | CqlSessionBuilder builder = options.dataStaxClusterBuilder();
245 | CqlSession session = builder.build();
246 | current = holders.compute(clientName, (k, h) -> h == null ? null : h.connected(session));
247 | if (current != null) {
248 | return current.session;
249 | } else {
250 | try {
251 | session.close();
252 | } catch (Exception ignored) {
253 | }
254 | throw new VertxException("Client closed while connecting", true);
255 | }
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/cassandra/impl/CassandraRowStreamImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Vert.x Community.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.cassandra.impl;
17 |
18 | import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
19 | import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
20 | import com.datastax.oss.driver.api.core.cql.Row;
21 | import io.vertx.cassandra.CassandraRowStream;
22 | import io.vertx.cassandra.ResultSet;
23 | import io.vertx.core.Context;
24 | import io.vertx.core.Future;
25 | import io.vertx.core.Handler;
26 | import io.vertx.core.internal.ContextInternal;
27 | import io.vertx.core.internal.EventExecutor;
28 | import io.vertx.core.internal.concurrent.InboundMessageQueue;
29 |
30 | import java.util.concurrent.locks.Lock;
31 | import java.util.concurrent.locks.ReentrantLock;
32 |
33 | /**
34 | * @author Pavel Drankou
35 | * @author Thomas Segismont
36 | */
37 | public class CassandraRowStreamImpl implements CassandraRowStream {
38 |
39 | private static final Object DONE = new Object();
40 |
41 | private final ContextInternal context;
42 | private final Queue internalQueue;
43 |
44 | private Handler rowHandler;
45 | private Handler exceptionHandler;
46 | private Handler endHandler;
47 |
48 | private ExecutionInfo executionInfo;
49 | private ColumnDefinitions columnDefinitions;
50 |
51 | public CassandraRowStreamImpl(Context context) {
52 |
53 | Queue queue = new Queue((ContextInternal) context);
54 | queue.pause();
55 |
56 | this.context = (ContextInternal) context;
57 | this.internalQueue = queue;
58 | }
59 |
60 | void init(ResultSet resultSet) {
61 | executionInfo = resultSet.getExecutionInfo();
62 | columnDefinitions = resultSet.getColumnDefinitions();
63 | internalQueue.init(resultSet);
64 | }
65 |
66 | @Override
67 | public synchronized CassandraRowStream exceptionHandler(Handler handler) {
68 | exceptionHandler = handler;
69 | return this;
70 | }
71 |
72 | @Override
73 | public CassandraRowStream handler(Handler handler) {
74 | synchronized (this) {
75 | rowHandler = handler;
76 | }
77 | if (handler == null) {
78 | pause();
79 | } else {
80 | resume();
81 | }
82 | return this;
83 | }
84 |
85 | @Override
86 | public synchronized CassandraRowStream endHandler(Handler handler) {
87 | endHandler = handler;
88 | return this;
89 | }
90 |
91 | @Override
92 | public CassandraRowStream pause() {
93 | internalQueue.pause();
94 | return this;
95 | }
96 |
97 | @Override
98 | public CassandraRowStream resume() {
99 | return fetch(Long.MAX_VALUE);
100 | }
101 |
102 | @Override
103 | public CassandraRowStream fetch(long l) {
104 | internalQueue.fetch(l);
105 | return this;
106 | }
107 |
108 | @Override
109 | public ExecutionInfo executionInfo() {
110 | return executionInfo;
111 | }
112 |
113 | @Override
114 | public ColumnDefinitions columnDefinitions() {
115 | return columnDefinitions;
116 | }
117 |
118 | private final Lock lock = new ReentrantLock();
119 | private final EventExecutor executor = new EventExecutor() {
120 | @Override
121 | public boolean inThread() {
122 | return true;
123 | }
124 | @Override
125 | public void execute(Runnable command) {
126 | lock.lock();
127 | try {
128 | command.run();
129 | } finally {
130 | lock.unlock();
131 | }
132 | }
133 | };
134 |
135 | private class Queue extends InboundMessageQueue