handler;
214 | synchronized (CassandraRowStreamImpl.this) {
215 | handler = exceptionHandler;
216 | }
217 | if (handler != null) {
218 | context.emit(err, handler);
219 | }
220 | }
221 | }
222 | }
223 |
224 | private static class StreamItem {
225 | public final ExecutionInfo executionInfo;
226 | public final ColumnDefinitions columnDefinitions;
227 | public final Row row;
228 |
229 | StreamItem(ResultSet resultSet, Row row) {
230 | this.executionInfo = resultSet.getExecutionInfo();
231 | this.columnDefinitions = resultSet.getColumnDefinitions();
232 | this.row = row;
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------