Skip to content

Commit 4fcbf62

Browse files
mjokMarius Jokūbauskas
and
Marius Jokūbauskas
authored
Changes for session and schema (#8)
This includes: - a new CassandraConnection constructor accepting an existing Cassandra session - Make of compliance sets (default, Liquibase) Co-authored-by: Marius Jokūbauskas <[email protected]>
1 parent c71f21b commit 4fcbf62

File tree

9 files changed

+300
-18
lines changed

9 files changed

+300
-18
lines changed

src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java

+82-16
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,26 @@
2222
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
2323
import com.datastax.oss.driver.api.core.metadata.Metadata;
2424
import com.datastax.oss.driver.api.core.session.Session;
25+
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
26+
import com.datastax.oss.driver.internal.core.type.codec.registry.DefaultCodecRegistry;
2527
import com.google.common.collect.Maps;
28+
import com.ing.data.cassandra.jdbc.codec.BigintToBigDecimalCodec;
29+
import com.ing.data.cassandra.jdbc.codec.DecimalToDoubleCodec;
30+
import com.ing.data.cassandra.jdbc.codec.FloatToDoubleCodec;
31+
import com.ing.data.cassandra.jdbc.codec.IntToLongCodec;
32+
import com.ing.data.cassandra.jdbc.codec.LongToIntCodec;
33+
import com.ing.data.cassandra.jdbc.codec.SmallintToIntCodec;
34+
import com.ing.data.cassandra.jdbc.codec.TimestampToLongCodec;
35+
import com.ing.data.cassandra.jdbc.codec.TinyintToIntCodec;
36+
import com.ing.data.cassandra.jdbc.codec.VarintToIntCodec;
37+
import com.ing.data.cassandra.jdbc.optionset.Default;
38+
import com.ing.data.cassandra.jdbc.optionset.OptionSet;
2639
import org.apache.commons.lang3.StringUtils;
2740
import org.slf4j.Logger;
2841
import org.slf4j.LoggerFactory;
2942

3043
import java.sql.Connection;
3144
import java.sql.DatabaseMetaData;
32-
import java.sql.ResultSet;
3345
import java.sql.SQLException;
3446
import java.sql.SQLFeatureNotSupportedException;
3547
import java.sql.SQLNonTransientConnectionException;
@@ -38,9 +50,11 @@
3850
import java.sql.Statement;
3951
import java.util.ArrayList;
4052
import java.util.HashMap;
53+
import java.util.Iterator;
4154
import java.util.List;
4255
import java.util.Map;
4356
import java.util.Properties;
57+
import java.util.ServiceLoader;
4458
import java.util.Set;
4559
import java.util.concurrent.ConcurrentMap;
4660
import java.util.concurrent.ConcurrentSkipListSet;
@@ -55,6 +69,7 @@
5569
import static com.ing.data.cassandra.jdbc.Utils.NO_TRANSACTIONS;
5670
import static com.ing.data.cassandra.jdbc.Utils.PROTOCOL;
5771
import static com.ing.data.cassandra.jdbc.Utils.TAG_ACTIVE_CQL_VERSION;
72+
import static com.ing.data.cassandra.jdbc.Utils.TAG_COMPLIANCE_MODE;
5873
import static com.ing.data.cassandra.jdbc.Utils.TAG_CONSISTENCY_LEVEL;
5974
import static com.ing.data.cassandra.jdbc.Utils.TAG_CQL_VERSION;
6075
import static com.ing.data.cassandra.jdbc.Utils.TAG_DATABASE_NAME;
@@ -117,6 +132,7 @@ public class CassandraConnection extends AbstractConnection implements Connectio
117132
private final boolean debugMode;
118133
private Properties clientInfo;
119134
private volatile boolean isClosed;
135+
private final OptionSet optionSet;
120136

121137
/**
122138
* Instantiates a new JDBC connection to a Cassandra cluster.
@@ -134,6 +150,7 @@ public CassandraConnection(final SessionHolder sessionHolder) throws SQLExceptio
134150
this.clientInfo = new Properties();
135151
this.url = PROTOCOL.concat(createSubName(sessionProperties));
136152
this.currentKeyspace = sessionProperties.getProperty(TAG_DATABASE_NAME);
153+
this.optionSet = lookupOptionSet(sessionProperties.getProperty(TAG_COMPLIANCE_MODE));
137154
this.username = sessionProperties.getProperty(TAG_USER,
138155
defaultConfigProfile.getString(DefaultDriverOption.AUTH_PROVIDER_USER_NAME, StringUtils.EMPTY));
139156
final String cqlVersion = sessionProperties.getProperty(TAG_CQL_VERSION, DEFAULT_CQL_VERSION);
@@ -166,6 +183,45 @@ public CassandraConnection(final SessionHolder sessionHolder) throws SQLExceptio
166183
});
167184
}
168185

186+
/**
187+
* Instantiates a new JDBC connection to a Cassandra cluster using preexisting session.
188+
* @param cSession Session to use
189+
* @param currentKeyspace Keyspace to use
190+
* @param defaultConsistencyLevel Consistency level
191+
* @param debugMode Debug mode flag
192+
* @param optionSet Compliance mode option set
193+
*/
194+
public CassandraConnection(final Session cSession, final String currentKeyspace,
195+
final ConsistencyLevel defaultConsistencyLevel,
196+
final boolean debugMode, final OptionSet optionSet) {
197+
this.sessionHolder = null;
198+
this.connectionProperties = new Properties();
199+
200+
if (optionSet == null) {
201+
this.optionSet = lookupOptionSet(null);
202+
} else {
203+
this.optionSet = optionSet;
204+
}
205+
206+
this.currentKeyspace = currentKeyspace;
207+
this.cSession = cSession;
208+
this.metadata = cSession.getMetadata();
209+
this.defaultConsistencyLevel = defaultConsistencyLevel;
210+
this.debugMode = debugMode;
211+
final List<TypeCodec<?>> codecs = new ArrayList<>();
212+
codecs.add(new TimestampToLongCodec());
213+
codecs.add(new LongToIntCodec());
214+
codecs.add(new IntToLongCodec());
215+
codecs.add(new BigintToBigDecimalCodec());
216+
codecs.add(new DecimalToDoubleCodec());
217+
codecs.add(new FloatToDoubleCodec());
218+
codecs.add(new VarintToIntCodec());
219+
codecs.add(new SmallintToIntCodec());
220+
codecs.add(new TinyintToIntCodec());
221+
222+
codecs.forEach(codec -> ((DefaultCodecRegistry) cSession.getContext().getCodecRegistry()).register(codec));
223+
}
224+
169225
/**
170226
* Checks whether the connection is closed.
171227
*
@@ -187,7 +243,9 @@ public void clearWarnings() throws SQLException {
187243

188244
@Override
189245
public void close() throws SQLException {
190-
this.sessionHolder.release();
246+
if (sessionHolder != null) {
247+
this.sessionHolder.release();
248+
}
191249
this.isClosed = true;
192250
}
193251

@@ -240,20 +298,7 @@ public void setAutoCommit(final boolean autoCommit) throws SQLException {
240298
@Override
241299
public String getCatalog() throws SQLException {
242300
checkNotClosed();
243-
244-
// It requires a query to table system.local since DataStax driver 4+.
245-
// If the query fails, return null.
246-
try (final Statement stmt = createStatement()) {
247-
final ResultSet rs = stmt.executeQuery("SELECT cluster_name FROM system.local");
248-
if (rs.next()) {
249-
return rs.getString("cluster_name");
250-
}
251-
} catch (final SQLException e) {
252-
LOG.warn("Unable to retrieve the cluster name.", e);
253-
return null;
254-
}
255-
256-
return null;
301+
return optionSet.getCatalog();
257302
}
258303

259304
@Override
@@ -504,4 +549,25 @@ public <T> T unwrap(final Class<T> iface) throws SQLException {
504549
throw new SQLFeatureNotSupportedException(String.format(NO_INTERFACE, iface.getSimpleName()));
505550
}
506551

552+
553+
public OptionSet getOptionSet() {
554+
return optionSet;
555+
}
556+
557+
private OptionSet lookupOptionSet(final String property) {
558+
final ServiceLoader<OptionSet> loader = ServiceLoader
559+
.load(OptionSet.class);
560+
final Iterator<OptionSet> iterator = loader.iterator();
561+
while (iterator.hasNext()) {
562+
final OptionSet optionSet = iterator.next();
563+
if (optionSet.getClass().getSimpleName().equalsIgnoreCase(property)) {
564+
optionSet.setConnection(this);
565+
return optionSet;
566+
}
567+
}
568+
final OptionSet optionSet = new Default();
569+
optionSet.setConnection(this);
570+
return optionSet;
571+
}
572+
507573
}

src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,7 @@ public ResultSet executeQuery(final String cql) throws SQLException {
416416
public int executeUpdate(final String cql) throws SQLException {
417417
checkNotClosed();
418418
doExecute(cql);
419-
// There is no updateCount available in Datastax Java driver, so return 0.
420-
return 0;
419+
return connection.getOptionSet().getSQLUpdateResponse();
421420
}
422421

423422
@Override

src/main/java/com/ing/data/cassandra/jdbc/Utils.java

+8
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ public final class Utils {
115115
* JDBC URL parameter key for the configuration file.
116116
*/
117117
public static final String KEY_CONFIG_FILE = "configfile";
118+
/**
119+
* JDBC URL parameter key for the compliance mode.
120+
*/
121+
public static final String KEY_COMPLIANCE_MODE = "compliancemode";
118122

119123
public static final String TAG_USER = "user";
120124
public static final String TAG_PASSWORD = "password";
@@ -135,6 +139,7 @@ public final class Utils {
135139
public static final String TAG_CLOUD_SECURE_CONNECT_BUNDLE = "secureConnectBundle";
136140
public static final String TAG_CONFIG_FILE = "configFile";
137141
public static final String TAG_REQUEST_TIMEOUT = "requestTimeout";
142+
public static final String TAG_COMPLIANCE_MODE = "complianceMode";
138143

139144
public static final String JSSE_TRUSTSTORE_PROPERTY = "javax.net.ssl.trustStore";
140145
public static final String JSSE_TRUSTSTORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword";
@@ -306,6 +311,9 @@ public static Properties parseURL(final String url) throws SQLException {
306311
if (params.containsKey(KEY_CONFIG_FILE)) {
307312
props.setProperty(TAG_CONFIG_FILE, params.get(KEY_CONFIG_FILE));
308313
}
314+
if (params.containsKey(KEY_COMPLIANCE_MODE)) {
315+
props.setProperty(TAG_COMPLIANCE_MODE, params.get(KEY_COMPLIANCE_MODE));
316+
}
309317
} else if (isDbaasConnection) {
310318
throw new SQLNonTransientConnectionException(SECURECONENCTBUNDLE_REQUIRED);
311319
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.ing.data.cassandra.jdbc.optionset;
17+
18+
import com.ing.data.cassandra.jdbc.CassandraConnection;
19+
20+
/**
21+
* Abstract option set to set common parameter used by option sets.
22+
*/
23+
public abstract class AbstractOptionSet implements OptionSet {
24+
25+
private CassandraConnection connection;
26+
27+
@Override
28+
public CassandraConnection getConnection() {
29+
return connection;
30+
}
31+
32+
public void setConnection(final CassandraConnection connection) {
33+
this.connection = connection;
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.ing.data.cassandra.jdbc.optionset;
17+
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
import java.sql.ResultSet;
22+
import java.sql.SQLException;
23+
import java.sql.Statement;
24+
25+
/**
26+
* Default Option set.
27+
*/
28+
29+
public class Default extends AbstractOptionSet {
30+
private static final Logger LOG = LoggerFactory.getLogger(AbstractOptionSet.class);
31+
32+
@Override
33+
public String getCatalog() {
34+
// It requires a query to table system.local since DataStax driver 4+.
35+
// If the query fails, return null.
36+
try (final Statement stmt = getConnection().createStatement()) {
37+
final ResultSet rs = stmt.executeQuery("SELECT cluster_name FROM system.local");
38+
if (rs.next()) {
39+
return rs.getString("cluster_name");
40+
}
41+
} catch (final SQLException e) {
42+
LOG.warn("Unable to retrieve the cluster name.", e);
43+
return null;
44+
}
45+
46+
return null;
47+
}
48+
49+
@Override
50+
public int getSQLUpdateResponse() {
51+
return 0;
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.ing.data.cassandra.jdbc.optionset;
17+
18+
/**
19+
* Option Set for liquibase compatability and flavour of JDBC.
20+
*/
21+
public class Liquibase extends AbstractOptionSet {
22+
23+
24+
@Override
25+
public String getCatalog() {
26+
return null;
27+
}
28+
29+
@Override
30+
public int getSQLUpdateResponse() {
31+
return -1;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.ing.data.cassandra.jdbc.optionset;
17+
18+
import com.ing.data.cassandra.jdbc.CassandraConnection;
19+
20+
/**
21+
* Option Set for compliance mode.
22+
* Different use cases require one or more adjustments to the wrapper, to be compatible.
23+
* Thus, OptionSet would provide convenience to set for different flavours.
24+
*
25+
*/
26+
public interface OptionSet {
27+
/**
28+
* There is no Catalog concept in cassandra. Different flavour requires different response.
29+
*
30+
* @return Catalog
31+
*/
32+
String getCatalog();
33+
34+
/**
35+
* There is no updateCount available in Datastax Java driver, different flavour requires different response.
36+
*
37+
* @return Predefined update response
38+
*/
39+
int getSQLUpdateResponse();
40+
41+
/**
42+
* Set referenced connection. See @{@link AbstractOptionSet}
43+
* @param connection Connection to set
44+
*/
45+
void setConnection(CassandraConnection connection);
46+
47+
/**
48+
* Get referenced connection. See @{@link AbstractOptionSet}
49+
*
50+
* @return referenced connection
51+
*/
52+
CassandraConnection getConnection();
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
com.ing.data.cassandra.jdbc.optionset.Liquibase
2+
com.ing.data.cassandra.jdbc.optionset.Default

0 commit comments

Comments
 (0)