Commit ca1710ee authored by Stephane Nicoll's avatar Stephane Nicoll

Upgrade to Apache Cassandra 4.3.1

See gh-19588
parent d282eb61
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; ...@@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.cassandra;
import java.util.Map; import java.util.Map;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
...@@ -44,7 +44,7 @@ import org.springframework.data.cassandra.core.CassandraOperations; ...@@ -44,7 +44,7 @@ import org.springframework.data.cassandra.core.CassandraOperations;
* @since 2.1.0 * @since 2.1.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Cluster.class, CassandraOperations.class }) @ConditionalOnClass({ CqlSession.class, CassandraOperations.class })
@ConditionalOnBean(CassandraOperations.class) @ConditionalOnBean(CassandraOperations.class)
@ConditionalOnEnabledHealthIndicator("cassandra") @ConditionalOnEnabledHealthIndicator("cassandra")
@AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, @AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,7 +17,7 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; ...@@ -17,7 +17,7 @@ package org.springframework.boot.actuate.autoconfigure.cassandra;
import java.util.Map; import java.util.Map;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration;
...@@ -43,7 +43,7 @@ import org.springframework.data.cassandra.core.ReactiveCassandraOperations; ...@@ -43,7 +43,7 @@ import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
* @since 2.1.0 * @since 2.1.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Cluster.class, ReactiveCassandraOperations.class, Flux.class }) @ConditionalOnClass({ CqlSession.class, ReactiveCassandraOperations.class, Flux.class })
@ConditionalOnBean(ReactiveCassandraOperations.class) @ConditionalOnBean(ReactiveCassandraOperations.class)
@ConditionalOnEnabledHealthIndicator("cassandra") @ConditionalOnEnabledHealthIndicator("cassandra")
@AutoConfigureAfter(CassandraReactiveDataAutoConfiguration.class) @AutoConfigureAfter(CassandraReactiveDataAutoConfiguration.class)
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
package org.springframework.boot.actuate.cassandra; package org.springframework.boot.actuate.cassandra;
import com.datastax.driver.core.ResultSet; import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.driver.core.querybuilder.Select;
import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
...@@ -53,9 +52,9 @@ public class CassandraHealthIndicator extends AbstractHealthIndicator { ...@@ -53,9 +52,9 @@ public class CassandraHealthIndicator extends AbstractHealthIndicator {
@Override @Override
protected void doHealthCheck(Health.Builder builder) throws Exception { protected void doHealthCheck(Health.Builder builder) throws Exception {
Select select = QueryBuilder.select("release_version").from("system", "local"); SimpleStatement select = SimpleStatement.newInstance("SELECT release_version FROM system.local");
ResultSet results = this.cassandraOperations.getCqlOperations().queryForResultSet(select); ResultSet results = this.cassandraOperations.getCqlOperations().queryForResultSet(select);
if (results.isExhausted()) { if (results.isFullyFetched()) {
builder.up(); builder.up();
return; return;
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
*/ */
package org.springframework.boot.actuate.cassandra; package org.springframework.boot.actuate.cassandra;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.driver.core.querybuilder.Select;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
...@@ -47,7 +46,7 @@ public class CassandraReactiveHealthIndicator extends AbstractReactiveHealthIndi ...@@ -47,7 +46,7 @@ public class CassandraReactiveHealthIndicator extends AbstractReactiveHealthIndi
@Override @Override
protected Mono<Health> doHealthCheck(Health.Builder builder) { protected Mono<Health> doHealthCheck(Health.Builder builder) {
Select select = QueryBuilder.select("release_version").from("system", "local"); SimpleStatement select = SimpleStatement.newInstance("SELECT release_version FROM system.local");
return this.reactiveCassandraOperations.getReactiveCqlOperations().queryForObject(select, String.class) return this.reactiveCassandraOperations.getReactiveCqlOperations().queryForObject(select, String.class)
.map((version) -> builder.up().withDetail("version", version).build()).single(); .map((version) -> builder.up().withDetail("version", version).build()).single();
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
package org.springframework.boot.actuate.cassandra; package org.springframework.boot.actuate.cassandra;
import com.datastax.driver.core.ResultSet; import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.driver.core.Row; import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
...@@ -51,8 +51,8 @@ class CassandraHealthIndicatorTests { ...@@ -51,8 +51,8 @@ class CassandraHealthIndicatorTests {
ResultSet resultSet = mock(ResultSet.class); ResultSet resultSet = mock(ResultSet.class);
CassandraHealthIndicator healthIndicator = new CassandraHealthIndicator(cassandraOperations); CassandraHealthIndicator healthIndicator = new CassandraHealthIndicator(cassandraOperations);
given(cassandraOperations.getCqlOperations()).willReturn(cqlOperations); given(cassandraOperations.getCqlOperations()).willReturn(cqlOperations);
given(cqlOperations.queryForResultSet(any(Select.class))).willReturn(resultSet); given(cqlOperations.queryForResultSet(any(SimpleStatement.class))).willReturn(resultSet);
given(resultSet.isExhausted()).willReturn(true); given(resultSet.isFullyFetched()).willReturn(true);
Health health = healthIndicator.health(); Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getStatus()).isEqualTo(Status.UP);
} }
...@@ -65,8 +65,8 @@ class CassandraHealthIndicatorTests { ...@@ -65,8 +65,8 @@ class CassandraHealthIndicatorTests {
Row row = mock(Row.class); Row row = mock(Row.class);
CassandraHealthIndicator healthIndicator = new CassandraHealthIndicator(cassandraOperations); CassandraHealthIndicator healthIndicator = new CassandraHealthIndicator(cassandraOperations);
given(cassandraOperations.getCqlOperations()).willReturn(cqlOperations); given(cassandraOperations.getCqlOperations()).willReturn(cqlOperations);
given(cqlOperations.queryForResultSet(any(Select.class))).willReturn(resultSet); given(cqlOperations.queryForResultSet(any(SimpleStatement.class))).willReturn(resultSet);
given(resultSet.isExhausted()).willReturn(false); given(resultSet.isFullyFetched()).willReturn(false);
given(resultSet.one()).willReturn(row); given(resultSet.one()).willReturn(row);
String expectedVersion = "1.0.0"; String expectedVersion = "1.0.0";
given(row.getString(0)).willReturn(expectedVersion); given(row.getString(0)).willReturn(expectedVersion);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package org.springframework.boot.actuate.cassandra; package org.springframework.boot.actuate.cassandra;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
...@@ -42,7 +42,8 @@ class CassandraReactiveHealthIndicatorTests { ...@@ -42,7 +42,8 @@ class CassandraReactiveHealthIndicatorTests {
@Test @Test
void testCassandraIsUp() { void testCassandraIsUp() {
ReactiveCqlOperations reactiveCqlOperations = mock(ReactiveCqlOperations.class); ReactiveCqlOperations reactiveCqlOperations = mock(ReactiveCqlOperations.class);
given(reactiveCqlOperations.queryForObject(any(Select.class), eq(String.class))).willReturn(Mono.just("6.0.0")); given(reactiveCqlOperations.queryForObject(any(SimpleStatement.class), eq(String.class)))
.willReturn(Mono.just("6.0.0"));
ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class); ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class);
given(reactiveCassandraOperations.getReactiveCqlOperations()).willReturn(reactiveCqlOperations); given(reactiveCassandraOperations.getReactiveCqlOperations()).willReturn(reactiveCqlOperations);
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -22,12 +22,10 @@ import java.util.ArrayList; ...@@ -22,12 +22,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.datastax.driver.core.ConsistencyLevel; import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
import com.datastax.driver.core.ProtocolOptions;
import com.datastax.driver.core.ProtocolOptions.Compression;
import com.datastax.driver.core.QueryOptions;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.boot.convert.DurationUnit; import org.springframework.boot.convert.DurationUnit;
/** /**
...@@ -48,19 +46,14 @@ public class CassandraProperties { ...@@ -48,19 +46,14 @@ public class CassandraProperties {
private String keyspaceName; private String keyspaceName;
/** /**
* Name of the Cassandra cluster. * Name of the Cassandra session.
*/ */
private String clusterName; private String sessionName;
/** /**
* Cluster node addresses. * Cluster node addresses in the form 'host:port'.
*/ */
private final List<String> contactPoints = new ArrayList<>(Collections.singleton("localhost")); private final List<String> contactPoints = new ArrayList<>(Collections.singleton("127.0.0.1:9042"));
/**
* Port of the Cassandra server.
*/
private int port = ProtocolOptions.DEFAULT_PORT;
/** /**
* Login user of the server. * Login user of the server.
...@@ -80,17 +73,17 @@ public class CassandraProperties { ...@@ -80,17 +73,17 @@ public class CassandraProperties {
/** /**
* Queries consistency level. * Queries consistency level.
*/ */
private ConsistencyLevel consistencyLevel; private DefaultConsistencyLevel consistencyLevel;
/** /**
* Queries serial consistency level. * Queries serial consistency level.
*/ */
private ConsistencyLevel serialConsistencyLevel; private DefaultConsistencyLevel serialConsistencyLevel;
/** /**
* Queries default fetch size. * Queries default page size.
*/ */
private int fetchSize = QueryOptions.DEFAULT_FETCH_SIZE; private int pageSize = 5000;
/** /**
* Socket option: connection time out. * Socket option: connection time out.
...@@ -112,12 +105,6 @@ public class CassandraProperties { ...@@ -112,12 +105,6 @@ public class CassandraProperties {
*/ */
private boolean ssl = false; private boolean ssl = false;
/**
* Whether to enable JMX reporting. Default to false as Cassandra JMX reporting is not
* compatible with Dropwizard Metrics.
*/
private boolean jmxEnabled;
/** /**
* Pool configuration. * Pool configuration.
*/ */
...@@ -131,24 +118,27 @@ public class CassandraProperties { ...@@ -131,24 +118,27 @@ public class CassandraProperties {
this.keyspaceName = keyspaceName; this.keyspaceName = keyspaceName;
} }
public String getClusterName() { public String getSessionName() {
return this.clusterName; return this.sessionName;
} }
public void setClusterName(String clusterName) { public void setSessionName(String sessionName) {
this.clusterName = clusterName; this.sessionName = sessionName;
} }
public List<String> getContactPoints() { @Deprecated
return this.contactPoints; @DeprecatedConfigurationProperty(replacement = "spring.data.cassandra.session-name")
public String getClusterName() {
return getSessionName();
} }
public int getPort() { @Deprecated
return this.port; public void setClusterName(String clusterName) {
setSessionName(clusterName);
} }
public void setPort(int port) { public List<String> getContactPoints() {
this.port = port; return this.contactPoints;
} }
public String getUsername() { public String getUsername() {
...@@ -175,28 +165,39 @@ public class CassandraProperties { ...@@ -175,28 +165,39 @@ public class CassandraProperties {
this.compression = compression; this.compression = compression;
} }
public ConsistencyLevel getConsistencyLevel() { public DefaultConsistencyLevel getConsistencyLevel() {
return this.consistencyLevel; return this.consistencyLevel;
} }
public void setConsistencyLevel(ConsistencyLevel consistency) { public void setConsistencyLevel(DefaultConsistencyLevel consistency) {
this.consistencyLevel = consistency; this.consistencyLevel = consistency;
} }
public ConsistencyLevel getSerialConsistencyLevel() { public DefaultConsistencyLevel getSerialConsistencyLevel() {
return this.serialConsistencyLevel; return this.serialConsistencyLevel;
} }
public void setSerialConsistencyLevel(ConsistencyLevel serialConsistency) { public void setSerialConsistencyLevel(DefaultConsistencyLevel serialConsistency) {
this.serialConsistencyLevel = serialConsistency; this.serialConsistencyLevel = serialConsistency;
} }
public int getPageSize() {
return this.pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
@Deprecated
@DeprecatedConfigurationProperty(replacement = "spring.data.cassandra.page-size")
public int getFetchSize() { public int getFetchSize() {
return this.fetchSize; return getPageSize();
} }
@Deprecated
public void setFetchSize(int fetchSize) { public void setFetchSize(int fetchSize) {
this.fetchSize = fetchSize; setPageSize(fetchSize);
} }
public Duration getConnectTimeout() { public Duration getConnectTimeout() {
...@@ -223,14 +224,6 @@ public class CassandraProperties { ...@@ -223,14 +224,6 @@ public class CassandraProperties {
this.ssl = ssl; this.ssl = ssl;
} }
public boolean isJmxEnabled() {
return this.jmxEnabled;
}
public void setJmxEnabled(boolean jmxEnabled) {
this.jmxEnabled = jmxEnabled;
}
public String getSchemaAction() { public String getSchemaAction() {
return this.schemaAction; return this.schemaAction;
} }
...@@ -255,11 +248,6 @@ public class CassandraProperties { ...@@ -255,11 +248,6 @@ public class CassandraProperties {
@DurationUnit(ChronoUnit.SECONDS) @DurationUnit(ChronoUnit.SECONDS)
private Duration idleTimeout = Duration.ofSeconds(120); private Duration idleTimeout = Duration.ofSeconds(120);
/**
* Pool timeout when trying to acquire a connection from a host's pool.
*/
private Duration poolTimeout = Duration.ofMillis(5000);
/** /**
* Heartbeat interval after which a message is sent on an idle connection to make * Heartbeat interval after which a message is sent on an idle connection to make
* sure it's still alive. If a duration suffix is not specified, seconds will be * sure it's still alive. If a duration suffix is not specified, seconds will be
...@@ -281,14 +269,6 @@ public class CassandraProperties { ...@@ -281,14 +269,6 @@ public class CassandraProperties {
this.idleTimeout = idleTimeout; this.idleTimeout = idleTimeout;
} }
public Duration getPoolTimeout() {
return this.poolTimeout;
}
public void setPoolTimeout(Duration poolTimeout) {
this.poolTimeout = poolTimeout;
}
public Duration getHeartbeatInterval() { public Duration getHeartbeatInterval() {
return this.heartbeatInterval; return this.heartbeatInterval;
} }
...@@ -307,4 +287,26 @@ public class CassandraProperties { ...@@ -307,4 +287,26 @@ public class CassandraProperties {
} }
/**
* Name of the algorithm used to compress protocol frames.
*/
public enum Compression {
/**
* Requires 'net.jpountz.lz4:lz4'.
*/
LZ4,
/**
* Requires org.xerial.snappy:snappy-java.
*/
SNAPPY,
/**
* No compression.
*/
NONE;
}
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,24 +16,24 @@ ...@@ -16,24 +16,24 @@
package org.springframework.boot.autoconfigure.cassandra; package org.springframework.boot.autoconfigure.cassandra;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Cluster.Builder; import com.datastax.oss.driver.api.core.CqlSessionBuilder;
/** /**
* Callback interface that can be implemented by beans wishing to customize the * Callback interface that can be implemented by beans wishing to customize the
* {@link Cluster} via a {@link Builder Cluster.Builder} whilst retaining default * {@link CqlSession} via a {@link CqlSessionBuilder} whilst retaining default
* auto-configuration. * auto-configuration.
* *
* @author Eddú Meléndez * @author Stephane Nicoll
* @since 1.5.0 * @since 2.3.0
*/ */
@FunctionalInterface @FunctionalInterface
public interface ClusterBuilderCustomizer { public interface CqlSessionBuilderCustomizer {
/** /**
* Customize the {@link Builder}. * Customize the {@link CqlSessionBuilder}.
* @param clusterBuilder the builder to customize * @param cqlSessionBuilder the builder to customize
*/ */
void customize(Builder clusterBuilder); void customize(CqlSessionBuilder cqlSessionBuilder);
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,24 +16,24 @@ ...@@ -16,24 +16,24 @@
package org.springframework.boot.autoconfigure.cassandra; package org.springframework.boot.autoconfigure.cassandra;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.driver.core.Cluster.Initializer; import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;
/** /**
* {@code ClusterFactory} provides control over the creation of a {@link Cluster} from an * Callback interface that can be implemented by beans wishing to customize the
* {@link Initializer}. * {@link DriverConfigLoader} via a {@link DriverConfigLoaderBuilderCustomizer} whilst
* retaining default auto-configuration.
* *
* @author Steffen F. Qvistgaard * @author Stephane Nicoll
* @since 2.2.0 * @since 2.3.0
*/ */
@FunctionalInterface public interface DriverConfigLoaderBuilderCustomizer {
public interface ClusterFactory {
/** /**
* Creates a {@link Cluster} from the given {@link Initializer}. * Customize the {@linkplain ProgrammaticDriverConfigLoaderBuilder DriverConfigLoader
* @param initializer the {@code Initializer} * builder}.
* @return the {@code Cluster} * @param builder the builder to customize
*/ */
Cluster create(Initializer initializer); void customizer(ProgrammaticDriverConfigLoaderBuilder builder);
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,28 +19,25 @@ package org.springframework.boot.autoconfigure.data.cassandra; ...@@ -19,28 +19,25 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Session;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.config.CassandraEntityClassScanner; import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.config.SessionFactoryFactoryBean;
import org.springframework.data.cassandra.core.CassandraAdminOperations; import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.core.CassandraTemplate;
...@@ -60,19 +57,15 @@ import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver; ...@@ -60,19 +57,15 @@ import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
* @since 1.3.0 * @since 1.3.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Cluster.class, CassandraAdminOperations.class }) @ConditionalOnClass({ CqlSession.class, CassandraAdminOperations.class })
@ConditionalOnBean(Cluster.class) @ConditionalOnBean(CqlSession.class)
@EnableConfigurationProperties(CassandraProperties.class)
@AutoConfigureAfter(CassandraAutoConfiguration.class) @AutoConfigureAfter(CassandraAutoConfiguration.class)
public class CassandraDataAutoConfiguration { public class CassandraDataAutoConfiguration {
private final CassandraProperties properties; private final CqlSession session;
private final Cluster cluster; public CassandraDataAutoConfiguration(CqlSession session) {
this.session = session;
public CassandraDataAutoConfiguration(CassandraProperties properties, Cluster cluster) {
this.properties = properties;
this.cluster = cluster;
} }
@Bean @Bean
...@@ -87,16 +80,11 @@ public class CassandraDataAutoConfiguration { ...@@ -87,16 +80,11 @@ public class CassandraDataAutoConfiguration {
if (!packages.isEmpty()) { if (!packages.isEmpty()) {
context.setInitialEntitySet(CassandraEntityClassScanner.scan(packages)); context.setInitialEntitySet(CassandraEntityClassScanner.scan(packages));
} }
PropertyMapper.get().from(this.properties::getKeyspaceName).whenHasText().as(this::createSimpleUserTypeResolver) context.setUserTypeResolver(new SimpleUserTypeResolver(this.session));
.to(context::setUserTypeResolver);
context.setCustomConversions(conversions); context.setCustomConversions(conversions);
return context; return context;
} }
private SimpleUserTypeResolver createSimpleUserTypeResolver(String keyspaceName) {
return new SimpleUserTypeResolver(this.cluster, keyspaceName);
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CassandraConverter cassandraConverter(CassandraMappingContext mapping, public CassandraConverter cassandraConverter(CassandraMappingContext mapping,
...@@ -107,12 +95,11 @@ public class CassandraDataAutoConfiguration { ...@@ -107,12 +95,11 @@ public class CassandraDataAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean(Session.class) @ConditionalOnMissingBean(SessionFactory.class)
public CassandraSessionFactoryBean cassandraSession(Environment environment, CassandraConverter converter) { public SessionFactoryFactoryBean cassandraSession(Environment environment, CassandraConverter converter) {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); SessionFactoryFactoryBean session = new SessionFactoryFactoryBean();
session.setCluster(this.cluster); session.setSession(this.session);
session.setConverter(converter); session.setConverter(converter);
session.setKeyspaceName(this.properties.getKeyspaceName());
Binder binder = Binder.get(environment); Binder binder = Binder.get(environment);
binder.bind("spring.data.cassandra.schema-action", SchemaAction.class).ifBound(session::setSchemaAction); binder.bind("spring.data.cassandra.schema-action", SchemaAction.class).ifBound(session::setSchemaAction);
return session; return session;
...@@ -120,8 +107,8 @@ public class CassandraDataAutoConfiguration { ...@@ -120,8 +107,8 @@ public class CassandraDataAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(CassandraOperations.class) @ConditionalOnMissingBean(CassandraOperations.class)
public CassandraTemplate cassandraTemplate(Session session, CassandraConverter converter) { public CassandraTemplate cassandraTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
return new CassandraTemplate(session, converter); return new CassandraTemplate(sessionFactory, converter);
} }
@Bean @Bean
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
package org.springframework.boot.autoconfigure.data.cassandra; package org.springframework.boot.autoconfigure.data.cassandra;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Session;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
...@@ -44,14 +43,14 @@ import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessio ...@@ -44,14 +43,14 @@ import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessio
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Cluster.class, ReactiveCassandraTemplate.class, Flux.class }) @ConditionalOnClass({ CqlSession.class, ReactiveCassandraTemplate.class, Flux.class })
@ConditionalOnBean(Session.class) @ConditionalOnBean(CqlSession.class)
@AutoConfigureAfter(CassandraDataAutoConfiguration.class) @AutoConfigureAfter(CassandraDataAutoConfiguration.class)
public class CassandraReactiveDataAutoConfiguration { public class CassandraReactiveDataAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ReactiveSession reactiveCassandraSession(Session session) { public ReactiveSession reactiveCassandraSession(CqlSession session) {
return new DefaultBridgedReactiveSession(session); return new DefaultBridgedReactiveSession(session);
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
package org.springframework.boot.autoconfigure.data.cassandra; package org.springframework.boot.autoconfigure.data.cassandra;
import com.datastax.driver.core.Session; import com.datastax.oss.driver.api.core.CqlSession;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
...@@ -38,7 +38,7 @@ import org.springframework.data.cassandra.repository.support.CassandraRepository ...@@ -38,7 +38,7 @@ import org.springframework.data.cassandra.repository.support.CassandraRepository
* @since 1.3.0 * @since 1.3.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Session.class, CassandraRepository.class }) @ConditionalOnClass({ CqlSession.class, CassandraRepository.class })
@ConditionalOnRepositoryType(store = "cassandra", type = RepositoryType.IMPERATIVE) @ConditionalOnRepositoryType(store = "cassandra", type = RepositoryType.IMPERATIVE)
@ConditionalOnMissingBean(CassandraRepositoryFactoryBean.class) @ConditionalOnMissingBean(CassandraRepositoryFactoryBean.class)
@Import(CassandraRepositoriesRegistrar.class) @Import(CassandraRepositoriesRegistrar.class)
......
...@@ -1557,6 +1557,33 @@ ...@@ -1557,6 +1557,33 @@
"level": "error" "level": "error"
} }
}, },
{
"name": "spring.data.cassandra.jmx-enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable JMX reporting. Default to false as Cassandra JMX reporting is not compatible with Dropwizard Metrics.",
"deprecation": {
"reason": "Cassandra no longer providers JMX metrics.",
"level": "error"
}
},
{
"name": "spring.data.cassandra.pool.pool-timeout",
"type": "java.time.Duration",
"description": "Pool timeout when trying to acquire a connection from a host's pool.",
"deprecation": {
"reason": "No longer available.",
"level": "error"
}
},
{
"name": "spring.data.cassandra.port",
"type": "java.lang.Integer",
"description": "Port of the Cassandra server.",
"deprecation": {
"reason": "each contact point must be of the form 'host:port'.",
"level": "error"
}
},
{ {
"name": "spring.data.cassandra.read-timeout-millis", "name": "spring.data.cassandra.read-timeout-millis",
"type": "java.lang.Integer", "type": "java.lang.Integer",
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
package org.springframework.boot.autoconfigure.cassandra; package org.springframework.boot.autoconfigure.cassandra;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.driver.core.Cluster.Initializer; import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.driver.core.PoolingOptions; import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigParseOptions;
import com.typesafe.config.impl.Parseable;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
...@@ -27,7 +30,6 @@ import org.springframework.context.annotation.Bean; ...@@ -27,7 +30,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link CassandraAutoConfiguration} * Tests for {@link CassandraAutoConfiguration}
...@@ -41,110 +43,66 @@ class CassandraAutoConfigurationTests { ...@@ -41,110 +43,66 @@ class CassandraAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class)); .withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class));
@Test @Test
void createClusterWithDefault() { void driverConfigLoaderWithDefaultConfiguration() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(DriverConfigLoader.class);
assertThat(context.getBean(Cluster.class).getClusterName()).startsWith("cluster"); assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.isDefined(DefaultDriverOption.SESSION_NAME)).isFalse();
}); });
} }
@Test @Test
void createClusterWithOverrides() { void driverConfigLoaderWithCustomSessionName() {
this.contextRunner.withPropertyValues("spring.data.cassandra.cluster-name=testcluster").run((context) -> { this.contextRunner.withPropertyValues("spring.data.cassandra.session-name=testcluster").run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(DriverConfigLoader.class);
assertThat(context.getBean(Cluster.class).getClusterName()).isEqualTo("testcluster"); assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo("testcluster");
}); });
} }
@Test @Test
void createCustomizeCluster() { void driverConfigLoaderWithCustomSessionNameAndCustomizer() {
this.contextRunner.withUserConfiguration(MockCustomizerConfig.class).run((context) -> { this.contextRunner.withUserConfiguration(SimpleDriverConfigLoaderBuilderCustomizerConfig.class)
assertThat(context).hasSingleBean(Cluster.class); .withPropertyValues("spring.data.cassandra.session-name=testcluster").run((context) -> {
assertThat(context).hasSingleBean(ClusterBuilderCustomizer.class); assertThat(context).hasSingleBean(DriverConfigLoader.class);
assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo("overridden-name");
}); });
} }
@Test @Test
void customizerOverridesAutoConfig() { void driverConfigLoaderApplyConsistentDefaults() {
this.contextRunner.withUserConfiguration(SimpleCustomizerConfig.class)
.withPropertyValues("spring.data.cassandra.cluster-name=testcluster").run((context) -> {
assertThat(context).hasSingleBean(Cluster.class);
assertThat(context.getBean(Cluster.class).getClusterName()).isEqualTo("overridden-name");
});
}
@Test
void defaultPoolOptions() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); Config defaultConfig = defaultConfig();
PoolingOptions poolingOptions = context.getBean(Cluster.class).getConfiguration().getPoolingOptions(); DriverExecutionProfile config = context.getBean(DriverConfigLoader.class).getInitialConfig()
assertThat(poolingOptions.getIdleTimeoutSeconds()).isEqualTo(PoolingOptions.DEFAULT_IDLE_TIMEOUT_SECONDS); .getDefaultProfile();
assertThat(poolingOptions.getPoolTimeoutMillis()).isEqualTo(PoolingOptions.DEFAULT_POOL_TIMEOUT_MILLIS); // TODO
assertThat(poolingOptions.getHeartbeatIntervalSeconds())
.isEqualTo(PoolingOptions.DEFAULT_HEARTBEAT_INTERVAL_SECONDS);
assertThat(poolingOptions.getMaxQueueSize()).isEqualTo(PoolingOptions.DEFAULT_MAX_QUEUE_SIZE);
}); });
} }
@Test @Test
void customizePoolOptions() { void driverConfigLoaderCustomizePoolOptions() {
this.contextRunner.withPropertyValues("spring.data.cassandra.pool.idle-timeout=42", this.contextRunner.withPropertyValues("spring.data.cassandra.pool.idle-timeout=42",
"spring.data.cassandra.pool.pool-timeout=52", "spring.data.cassandra.pool.heartbeat-interval=62", "spring.data.cassandra.pool.heartbeat-interval=62", "spring.data.cassandra.pool.max-queue-size=72")
"spring.data.cassandra.pool.max-queue-size=72").run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); DriverExecutionProfile config = context.getBean(DriverConfigLoader.class).getInitialConfig()
PoolingOptions poolingOptions = context.getBean(Cluster.class).getConfiguration() .getDefaultProfile();
.getPoolingOptions(); assertThat(config.getInt(DefaultDriverOption.HEARTBEAT_TIMEOUT)).isEqualTo(42);
assertThat(poolingOptions.getIdleTimeoutSeconds()).isEqualTo(42); assertThat(config.getInt(DefaultDriverOption.HEARTBEAT_INTERVAL)).isEqualTo(62);
assertThat(poolingOptions.getPoolTimeoutMillis()).isEqualTo(52); assertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(72);
assertThat(poolingOptions.getHeartbeatIntervalSeconds()).isEqualTo(62);
assertThat(poolingOptions.getMaxQueueSize()).isEqualTo(72);
}); });
} }
@Test private static Config defaultConfig() {
void clusterFactoryIsCalledToCreateCluster() { return Parseable.newResources("reference.conf", ConfigParseOptions.defaults()).parse().toConfig();
this.contextRunner.withUserConfiguration(ClusterFactoryConfig.class)
.run((context) -> assertThat(context.getBean(TestClusterFactory.class).initializer).isNotNull());
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class MockCustomizerConfig { static class SimpleDriverConfigLoaderBuilderCustomizerConfig {
@Bean @Bean
ClusterBuilderCustomizer customizer() { DriverConfigLoaderBuilderCustomizer customizer() {
return mock(ClusterBuilderCustomizer.class); return (builder) -> builder.withString(DefaultDriverOption.SESSION_NAME, "overridden-name");
}
}
@Configuration(proxyBeanMethods = false)
static class SimpleCustomizerConfig {
@Bean
ClusterBuilderCustomizer customizer() {
return (clusterBuilder) -> clusterBuilder.withClusterName("overridden-name");
}
}
@Configuration(proxyBeanMethods = false)
static class ClusterFactoryConfig {
@Bean
TestClusterFactory clusterFactory() {
return new TestClusterFactory();
}
}
static class TestClusterFactory implements ClusterFactory {
private Initializer initializer = null;
@Override
public Cluster create(Initializer initializer) {
this.initializer = initializer;
return Cluster.buildFrom(initializer);
} }
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
package org.springframework.boot.autoconfigure.data.cassandra; package org.springframework.boot.autoconfigure.data.cassandra;
import java.net.InetSocketAddress;
import java.time.Duration; import java.time.Duration;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Session;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
...@@ -29,11 +29,14 @@ import org.testcontainers.junit.jupiter.Testcontainers; ...@@ -29,11 +29,14 @@ import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer;
import org.springframework.boot.autoconfigure.data.cassandra.city.City; import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.config.SessionFactoryFactoryBean;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -55,8 +58,9 @@ class CassandraDataAutoConfigurationIntegrationTests { ...@@ -55,8 +58,9 @@ class CassandraDataAutoConfigurationIntegrationTests {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class);
TestPropertyValues TestPropertyValues
.of("spring.data.cassandra.port=" + cassandra.getFirstMappedPort(), .of("spring.data.cassandra.contact-points:localhost:" + cassandra.getFirstMappedPort(),
"spring.data.cassandra.read-timeout=24000", "spring.data.cassandra.connect-timeout=10000") "spring.data.cassandra.read-timeout=24000", "spring.data.cassandra.connect-timeout=10000")
.applyTo(this.context.getEnvironment()); .applyTo(this.context.getEnvironment());
} }
...@@ -74,8 +78,8 @@ class CassandraDataAutoConfigurationIntegrationTests { ...@@ -74,8 +78,8 @@ class CassandraDataAutoConfigurationIntegrationTests {
AutoConfigurationPackages.register(this.context, cityPackage); AutoConfigurationPackages.register(this.context, cityPackage);
this.context.register(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class); this.context.register(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
CassandraSessionFactoryBean bean = this.context.getBean(CassandraSessionFactoryBean.class); assertThat(this.context.getBean(SessionFactoryFactoryBean.class)).hasFieldOrPropertyWithValue("schemaAction",
assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.NONE); SchemaAction.NONE);
} }
@Test @Test
...@@ -87,17 +91,28 @@ class CassandraDataAutoConfigurationIntegrationTests { ...@@ -87,17 +91,28 @@ class CassandraDataAutoConfigurationIntegrationTests {
"spring.data.cassandra.keyspaceName=boot_test").applyTo(this.context); "spring.data.cassandra.keyspaceName=boot_test").applyTo(this.context);
this.context.register(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class); this.context.register(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
CassandraSessionFactoryBean bean = this.context.getBean(CassandraSessionFactoryBean.class); assertThat(this.context.getBean(SessionFactoryFactoryBean.class)).hasFieldOrPropertyWithValue("schemaAction",
assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.RECREATE_DROP_UNUSED); SchemaAction.RECREATE_DROP_UNUSED);
} }
private void createTestKeyspaceIfNotExists() { private void createTestKeyspaceIfNotExists() {
Cluster cluster = Cluster.builder().withoutJMXReporting().withPort(cassandra.getFirstMappedPort()) try (CqlSession session = CqlSession.builder()
.addContactPoint(cassandra.getContainerIpAddress()).build(); .addContactPoint(
try (Session session = cluster.connect()) { new InetSocketAddress(cassandra.getContainerIpAddress(), cassandra.getFirstMappedPort()))
.withLocalDatacenter("datacenter1").build()) {
session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test" session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test"
+ " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"); + " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
} }
} }
@Configuration
static class TestConfiguration {
@Bean
CqlSessionBuilderCustomizer sessionCustomizer() {
return (builder) -> builder.withLocalDatacenter("datacenter1");
}
}
} }
...@@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.data.cassandra; ...@@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import com.datastax.driver.core.Session; import com.datastax.oss.driver.api.core.CqlSession;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
...@@ -101,7 +101,7 @@ class CassandraDataAutoConfigurationTests { ...@@ -101,7 +101,7 @@ class CassandraDataAutoConfigurationTests {
@Test @Test
void clusterDoesNotExist() { void clusterDoesNotExist() {
this.context = new AnnotationConfigApplicationContext(CassandraDataAutoConfiguration.class); this.context = new AnnotationConfigApplicationContext(CassandraDataAutoConfiguration.class);
assertThat(this.context.getBeansOfType(Session.class)).isEmpty(); assertThat(this.context.getBeansOfType(CqlSession.class)).isEmpty();
} }
void load(Class<?>... config) { void load(Class<?>... config) {
...@@ -119,8 +119,8 @@ class CassandraDataAutoConfigurationTests { ...@@ -119,8 +119,8 @@ class CassandraDataAutoConfigurationTests {
static class TestConfiguration { static class TestConfiguration {
@Bean @Bean
Session getObject() { CqlSession cqlSession() {
return mock(Session.class); return mock(CqlSession.class);
} }
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,7 +18,7 @@ package org.springframework.boot.autoconfigure.data.cassandra; ...@@ -18,7 +18,7 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Set; import java.util.Set;
import com.datastax.driver.core.Session; import com.datastax.oss.driver.api.core.CqlSession;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
...@@ -99,8 +99,8 @@ class CassandraReactiveDataAutoConfigurationTests { ...@@ -99,8 +99,8 @@ class CassandraReactiveDataAutoConfigurationTests {
static class TestConfiguration { static class TestConfiguration {
@Bean @Bean
Session session() { CqlSession cqlSession() {
return mock(Session.class); return mock(CqlSession.class);
} }
} }
......
...@@ -18,8 +18,8 @@ package org.springframework.boot.autoconfigure.data.cassandra; ...@@ -18,8 +18,8 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Set; import java.util.Set;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Session; import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
...@@ -61,7 +61,7 @@ class CassandraReactiveRepositoriesAutoConfigurationTests { ...@@ -61,7 +61,7 @@ class CassandraReactiveRepositoriesAutoConfigurationTests {
void testDefaultRepositoryConfiguration() { void testDefaultRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ReactiveCityRepository.class); assertThat(context).hasSingleBean(ReactiveCityRepository.class);
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(CqlSessionBuilder.class);
assertThat(getInitialEntitySet(context)).hasSize(1); assertThat(getInitialEntitySet(context)).hasSize(1);
}); });
} }
...@@ -69,7 +69,7 @@ class CassandraReactiveRepositoriesAutoConfigurationTests { ...@@ -69,7 +69,7 @@ class CassandraReactiveRepositoriesAutoConfigurationTests {
@Test @Test
void testNoRepositoryConfiguration() { void testNoRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(CqlSessionBuilder.class);
assertThat(getInitialEntitySet(context)).isEmpty(); assertThat(getInitialEntitySet(context)).isEmpty();
}); });
} }
...@@ -106,8 +106,8 @@ class CassandraReactiveRepositoriesAutoConfigurationTests { ...@@ -106,8 +106,8 @@ class CassandraReactiveRepositoriesAutoConfigurationTests {
static class TestConfiguration { static class TestConfiguration {
@Bean @Bean
Session session() { CqlSession cqlSession() {
return mock(Session.class); return mock(CqlSession.class);
} }
} }
......
...@@ -18,8 +18,8 @@ package org.springframework.boot.autoconfigure.data.cassandra; ...@@ -18,8 +18,8 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Set; import java.util.Set;
import com.datastax.driver.core.Cluster; import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.driver.core.Session; import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
...@@ -59,7 +59,7 @@ class CassandraRepositoriesAutoConfigurationTests { ...@@ -59,7 +59,7 @@ class CassandraRepositoriesAutoConfigurationTests {
void testDefaultRepositoryConfiguration() { void testDefaultRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(CityRepository.class); assertThat(context).hasSingleBean(CityRepository.class);
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(CqlSessionBuilder.class);
assertThat(getInitialEntitySet(context)).hasSize(1); assertThat(getInitialEntitySet(context)).hasSize(1);
}); });
} }
...@@ -67,7 +67,7 @@ class CassandraRepositoriesAutoConfigurationTests { ...@@ -67,7 +67,7 @@ class CassandraRepositoriesAutoConfigurationTests {
@Test @Test
void testNoRepositoryConfiguration() { void testNoRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Cluster.class); assertThat(context).hasSingleBean(CqlSessionBuilder.class);
assertThat(getInitialEntitySet(context)).isEmpty(); assertThat(getInitialEntitySet(context)).isEmpty();
}); });
} }
...@@ -104,8 +104,8 @@ class CassandraRepositoriesAutoConfigurationTests { ...@@ -104,8 +104,8 @@ class CassandraRepositoriesAutoConfigurationTests {
static class TestConfiguration { static class TestConfiguration {
@Bean @Bean
Session session() { CqlSession cqlSession() {
return mock(Session.class); return mock(CqlSession.class);
} }
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
package org.springframework.boot.autoconfigure.data.cassandra.city; package org.springframework.boot.autoconfigure.data.cassandra.city;
import com.datastax.driver.core.DataType.Name;
import org.springframework.data.cassandra.core.mapping.CassandraType; import org.springframework.data.cassandra.core.mapping.CassandraType;
import org.springframework.data.cassandra.core.mapping.CassandraType.Name;
import org.springframework.data.cassandra.core.mapping.Column; import org.springframework.data.cassandra.core.mapping.Column;
import org.springframework.data.cassandra.core.mapping.PrimaryKey; import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table; import org.springframework.data.cassandra.core.mapping.Table;
......
...@@ -159,11 +159,11 @@ bom { ...@@ -159,11 +159,11 @@ bom {
] ]
} }
} }
library('Cassandra Driver', '3.7.2') { library('Cassandra Driver', '4.3.1') {
group('com.datastax.cassandra') { group('com.datastax.oss') {
modules = [ modules = [
'cassandra-driver-core', 'java-driver-core',
'cassandra-driver-mapping' 'java-driver-query-builder'
] ]
} }
} }
......
...@@ -6,7 +6,7 @@ plugins { ...@@ -6,7 +6,7 @@ plugins {
description = 'Spring Boot Testing Support' description = 'Spring Boot Testing Support'
dependencies { dependencies {
compileOnly "com.datastax.cassandra:cassandra-driver-core" compileOnly "com.datastax.oss:java-driver-core"
compileOnly "javax.servlet:javax.servlet-api" compileOnly "javax.servlet:javax.servlet-api"
compileOnly "junit:junit" compileOnly "junit:junit"
compileOnly "org.junit.jupiter:junit-jupiter" compileOnly "org.junit.jupiter:junit-jupiter"
......
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.cassandra;
import java.util.UUID;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;
@Table
public class Customer {
@PrimaryKey
private UUID id;
private String firstName;
private String lastName;
public Customer() {
}
public Customer(UUID id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%s, firstName='%s', lastName='%s']", this.id, this.firstName, this.lastName);
}
}
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.cassandra;
import java.util.List;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, String> {
@Query("Select * from customer where firstname=?0")
Customer findByFirstName(String firstName);
@Query("Select * from customer where lastname=?0")
List<Customer> findByLastName(String lastName);
}
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.cassandra;
import com.datastax.driver.core.utils.UUIDs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleCassandraApplication implements CommandLineRunner {
@Autowired
private CustomerRepository repository;
@Override
public void run(String... args) throws Exception {
this.repository.deleteAll();
// save a couple of customers
this.repository.save(new Customer(UUIDs.timeBased(), "Alice", "Smith"));
this.repository.save(new Customer(UUIDs.timeBased(), "Bob", "Smith"));
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : this.repository.findAll()) {
System.out.println(customer);
}
System.out.println();
// fetch an individual customer
System.out.println("Customer found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(this.repository.findByFirstName("Alice"));
System.out.println("Customers found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Customer customer : this.repository.findByLastName("Smith")) {
System.out.println(customer);
}
}
public static void main(String[] args) {
SpringApplication.run(SampleCassandraApplication.class, args);
}
}
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.cassandra;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cassandraunit.spring.CassandraUnitDependencyInjectionTestExecutionListener;
import org.springframework.core.Ordered;
public class OrderedCassandraTestExecutionListener extends CassandraUnitDependencyInjectionTestExecutionListener {
private static final Log logger = LogFactory.getLog(OrderedCassandraTestExecutionListener.class);
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
protected void cleanServer() {
try {
super.cleanServer();
}
catch (Exception ex) {
logger.warn("Failure during server cleanup", ex);
}
}
}
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.cassandra;
import java.io.File;
import org.cassandraunit.spring.CassandraDataSet;
import org.cassandraunit.spring.EmbeddedCassandra;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestExecutionListeners.MergeMode;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SampleCassandraApplication}.
*/
@TestExecutionListeners(mergeMode = MergeMode.MERGE_WITH_DEFAULTS,
listeners = { OrderedCassandraTestExecutionListener.class })
@ExtendWith(OutputCaptureExtension.class)
@SpringBootTest
@CassandraDataSet(keyspace = "mykeyspace", value = "setup.cql")
@EmbeddedCassandra(timeout = 60000)
class SampleCassandraApplicationTests {
@Test
void testDefaultSettings(CapturedOutput output) {
Assumptions.assumeFalse(this::runningOnWindows);
assertThat(output).contains("firstName='Alice', lastName='Smith'");
}
private boolean runningOnWindows() {
return File.separatorChar == '\\';
}
}
CREATE TABLE customer (id TimeUUID PRIMARY KEY, firstname text, lastname text);
CREATE INDEX customerfistnameindex ON customer (firstname);
CREATE INDEX customersecondnameindex ON customer (lastname);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment