Add Cassandra support

Add auto-configuration support and health checks for Cassandra and
Spring Data Cassandra.

Fixes gh-2064
Closes gh-2214
This commit is contained in:
Julien Dubois 2014-12-22 11:06:37 +01:00 committed by Phillip Webb
parent 49fab4a60f
commit c401330901
32 changed files with 1417 additions and 4 deletions

View File

@ -147,6 +147,11 @@
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.health;
import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.util.Assert;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
/**
* Simple implementation of a {@link HealthIndicator} returning status information for
* Cassandra data stores.
*
* @author Julien Dubois
* @since 1.3.0
*/
public class CassandraHealthIndicator extends AbstractHealthIndicator {
private CassandraAdminOperations cassandraAdminOperations;
/**
* Create a new {@link CassandraHealthIndicator} instance.
* @param cassandraAdminOperations the Cassandra admin operations
*/
public CassandraHealthIndicator(CassandraAdminOperations cassandraAdminOperations) {
Assert.notNull(cassandraAdminOperations,
"CassandraAdminOperations must not be null");
this.cassandraAdminOperations = cassandraAdminOperations;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
Select select = QueryBuilder.select("release_version")
.from("system", "local");
ResultSet results = this.cassandraAdminOperations.query(select);
if (results.isExhausted()) {
builder.up();
return;
}
String version = results.one().getString(0);
builder.up().withDetail("version", version);
}
catch (Exception ex) {
builder.down(ex);
}
}
}

View File

@ -342,6 +342,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>

View File

@ -0,0 +1,107 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.cassandra;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.QueryOptions;
import com.datastax.driver.core.SocketOptions;
import com.datastax.driver.core.policies.LoadBalancingPolicy;
import com.datastax.driver.core.policies.ReconnectionPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Cassandra.
*
* @author Julien Dubois
* @author Phillip Webb
* @since 1.3.0
*/
@Configuration
@ConditionalOnClass({ Cluster.class })
@EnableConfigurationProperties(CassandraProperties.class)
public class CassandraAutoConfiguration {
@Autowired
private CassandraProperties properties;
@Bean
@ConditionalOnMissingBean
public Cluster cluster() {
CassandraProperties properties = this.properties;
Cluster.Builder builder = Cluster.builder()
.withClusterName(properties.getClusterName())
.withPort(properties.getPort());
if (properties.getCompression() != null) {
builder.withCompression(properties.getCompression());
}
if (properties.getLoadBalancingPolicy() != null) {
LoadBalancingPolicy policy = instantiate(properties.getLoadBalancingPolicy());
builder.withLoadBalancingPolicy(policy);
}
builder.withQueryOptions(getQueryOptions());
if (properties.getReconnectionPolicy() != null) {
ReconnectionPolicy policy = instantiate(properties.getReconnectionPolicy());
builder.withReconnectionPolicy(policy);
}
if (properties.getRetryPolicy() != null) {
RetryPolicy policy = instantiate(properties.getRetryPolicy());
builder.withRetryPolicy(policy);
}
builder.withSocketOptions(getSocketOptions());
if (properties.isSsl()) {
builder.withSSL();
}
String points = properties.getContactPoints();
builder.addContactPoints(StringUtils.commaDelimitedListToStringArray(points));
return builder.build();
}
public static <T> T instantiate(Class<T> type) {
return BeanUtils.instantiate(type);
}
private QueryOptions getQueryOptions() {
QueryOptions options = new QueryOptions();
CassandraProperties properties = this.properties;
if (properties.getConsistencyLevel() != null) {
options.setConsistencyLevel(properties.getConsistencyLevel());
}
if (properties.getSerialConsistencyLevel() != null) {
options.setSerialConsistencyLevel(properties.getSerialConsistencyLevel());
}
options.setFetchSize(properties.getFetchSize());
return options;
}
private SocketOptions getSocketOptions() {
SocketOptions options = new SocketOptions();
options.setConnectTimeoutMillis(this.properties.getConnectTimeoutMillis());
options.setReadTimeoutMillis(this.properties.getReadTimeoutMillis());
return options;
}
}

View File

@ -0,0 +1,224 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.cassandra;
import org.springframework.boot.context.properties.ConfigurationProperties;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.ProtocolOptions;
import com.datastax.driver.core.ProtocolOptions.Compression;
import com.datastax.driver.core.QueryOptions;
import com.datastax.driver.core.SocketOptions;
import com.datastax.driver.core.policies.LoadBalancingPolicy;
import com.datastax.driver.core.policies.ReconnectionPolicy;
import com.datastax.driver.core.policies.RetryPolicy;
/**
* Configuration properties for Cassandra.
*
* @author Julien Dubois
* @author Phillip Webb
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "spring.data.cassandra")
public class CassandraProperties {
/**
* Keyspace name to use.
*/
private String keyspaceName;
/**
* Name of the Cassandra cluster.
*/
private String clusterName;
/**
* Comma-separated list of cluster node addresses.
*/
private String contactPoints = "localhost";
/**
* Port of the Cassandra server.
*/
private int port = ProtocolOptions.DEFAULT_PORT;
/**
* Compression supported by the Cassandra binary protocol.
*/
private Compression compression = Compression.NONE;
/**
* Class name of the load balancing policy.
*/
private Class<? extends LoadBalancingPolicy> loadBalancingPolicy;
/**
* Queries consistency level.
*/
private ConsistencyLevel consistencyLevel;
/**
* Queries serial consistency level.
*/
private ConsistencyLevel serialConsistencyLevel;
/**
* Queries default fetch size.
*/
private int fetchSize = QueryOptions.DEFAULT_FETCH_SIZE;
/**
* Reconnection policy class.
*/
private Class<? extends ReconnectionPolicy> reconnectionPolicy;
/**
* Class name of the retry policy.
*/
private Class<? extends RetryPolicy> retryPolicy;
/**
* Socket option: connection time out.
*/
private int connectTimeoutMillis = SocketOptions.DEFAULT_CONNECT_TIMEOUT_MILLIS;
/**
* Socket option: read time out.
*/
private int readTimeoutMillis = SocketOptions.DEFAULT_READ_TIMEOUT_MILLIS;
/**
* Enable SSL support.
*/
private boolean ssl = false;
public String getKeyspaceName() {
return this.keyspaceName;
}
public void setKeyspaceName(String keyspaceName) {
this.keyspaceName = keyspaceName;
}
public String getClusterName() {
return this.clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getContactPoints() {
return this.contactPoints;
}
public void setContactPoints(String contactPoints) {
this.contactPoints = contactPoints;
}
public int getPort() {
return this.port;
}
public void setPort(int port) {
this.port = port;
}
public Compression getCompression() {
return this.compression;
}
public void setCompression(Compression compression) {
this.compression = compression;
}
public Class<? extends LoadBalancingPolicy> getLoadBalancingPolicy() {
return this.loadBalancingPolicy;
}
public void setLoadBalancingPolicy(
Class<? extends LoadBalancingPolicy> loadBalancingPolicy) {
this.loadBalancingPolicy = loadBalancingPolicy;
}
public ConsistencyLevel getConsistencyLevel() {
return this.consistencyLevel;
}
public void setConsistencyLevel(ConsistencyLevel consistency) {
this.consistencyLevel = consistency;
}
public ConsistencyLevel getSerialConsistencyLevel() {
return this.serialConsistencyLevel;
}
public void setSerialConsistencyLevel(ConsistencyLevel serialConsistency) {
this.serialConsistencyLevel = serialConsistency;
}
public int getFetchSize() {
return this.fetchSize;
}
public void setFetchSize(int fetchSize) {
this.fetchSize = fetchSize;
}
public Class<? extends ReconnectionPolicy> getReconnectionPolicy() {
return this.reconnectionPolicy;
}
public void setReconnectionPolicy(
Class<? extends ReconnectionPolicy> reconnectionPolicy) {
this.reconnectionPolicy = reconnectionPolicy;
}
public Class<? extends RetryPolicy> getRetryPolicy() {
return this.retryPolicy;
}
public void setRetryPolicy(Class<? extends RetryPolicy> retryPolicy) {
this.retryPolicy = retryPolicy;
}
public int getConnectTimeoutMillis() {
return this.connectTimeoutMillis;
}
public void setConnectTimeoutMillis(int connectTimeoutMillis) {
this.connectTimeoutMillis = connectTimeoutMillis;
}
public int getReadTimeoutMillis() {
return this.readTimeoutMillis;
}
public void setReadTimeoutMillis(int readTimeoutMillis) {
this.readTimeoutMillis = readTimeoutMillis;
}
public boolean isSsl() {
return this.ssl;
}
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for Cassandra.
*/
package org.springframework.boot.autoconfigure.cassandra;

View File

@ -0,0 +1,91 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra support.
*
* @author Julien Dubois
* @author Eddú Meléndez
* @since 1.3.0
*/
@Configuration
@ConditionalOnClass({ Cluster.class, CassandraAdminOperations.class })
@EnableConfigurationProperties(CassandraProperties.class)
@AutoConfigureAfter(CassandraAutoConfiguration.class)
public class CassandraDataAutoConfiguration {
@Autowired
private CassandraProperties properties;
@Autowired
private Cluster cluster;
@Bean
@ConditionalOnMissingBean
public CassandraMappingContext cassandraMapping() {
return new BasicCassandraMappingContext();
}
@Bean
@ConditionalOnMissingBean
public CassandraConverter cassandraConverter(CassandraMappingContext mapping) {
return new MappingCassandraConverter(mapping);
}
@Bean
@ConditionalOnMissingBean
public CassandraSessionFactoryBean session(CassandraConverter converter)
throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(this.cluster);
session.setConverter(converter);
session.setKeyspaceName(this.properties.getKeyspaceName());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
@Bean
@ConditionalOnMissingBean
public CassandraTemplate cassandraTemplate(Session session,
CassandraConverter converter) throws Exception {
return new CassandraTemplate(session, converter);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
import com.datastax.driver.core.Session;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra
* Repositories.
*
* @author Eddú Meléndez
* @see EnableCassandraRepositories
* @since 1.3.0
*/
@Configuration
@ConditionalOnClass({ Session.class, CassandraRepository.class })
@ConditionalOnProperty(prefix = "spring.data.cassandra.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean(CassandraRepositoryFactoryBean.class)
@Import(CassandraRepositoriesAutoConfigureRegistrar.class)
public class CassandraRepositoriesAutoConfiguration {
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra;
import java.lang.annotation.Annotation;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.cassandra.repository.config.CassandraRepositoryConfigurationExtension;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Cassandra
* Repositories.
*
* @author Eddú Meléndez
* @since 1.3.0
*/
class CassandraRepositoriesAutoConfigureRegistrar extends
AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableCassandraRepositories.class;
}
@Override
protected Class<?> getConfiguration() {
return EnableCassandraRepositoriesConfiguration.class;
}
@Override
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
return new CassandraRepositoryConfigurationExtension();
}
@EnableCassandraRepositories
private static class EnableCassandraRepositoriesConfiguration {
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for Spring Data Cassandra.
*/
package org.springframework.boot.autoconfigure.data.cassandra;

View File

@ -11,9 +11,12 @@ org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.cassandra;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.datastax.driver.core.Cluster;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link CassandraAutoConfiguration}
*
* @author Eddú Meléndez
*/
public class CassandraAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@After
public void tearDown() throws Exception {
if (this.context != null) {
this.context.close();
}
}
@Test
public void createClusterWithDefault() {
this.context = doLoad();
assertEquals(1, this.context.getBeanNamesForType(Cluster.class).length);
Cluster cluster = this.context.getBean(Cluster.class);
assertThat(cluster.getClusterName(), startsWith("cluster"));
}
@Test
public void createClusterWithOverrides() {
this.context = doLoad("spring.data.cassandra.cluster-name=testcluster");
assertEquals(1, this.context.getBeanNamesForType(Cluster.class).length);
Cluster cluster = this.context.getBean(Cluster.class);
assertThat(cluster.getClusterName(), equalTo("testcluster"));
}
private AnnotationConfigApplicationContext doLoad(String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.register(PropertyPlaceholderAutoConfiguration.class,
CassandraAutoConfiguration.class);
applicationContext.refresh();
return applicationContext;
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.alt.cassandra;
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.data.repository.Repository;
public interface CityCassandraRepository extends Repository<City, Long> {
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.cassandra.core.CassandraTemplate;
import com.datastax.driver.core.Session;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link CassandraDataAutoConfiguration}
*
* @author Eddú Meléndez
*/
public class CassandraDataAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void templateExists() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestExcludeConfiguration.class, TestConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class);
this.context.refresh();
assertEquals(1, this.context.getBeanNamesForType(CassandraTemplate.class).length);
}
@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(classes = { Session.class }, type = FilterType.ASSIGNABLE_TYPE))
static class TestExcludeConfiguration {
}
@Configuration
static class TestConfiguration {
@Bean
public Session getObject() {
return mock(Session.class);
}
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.alt.cassandra.CityCassandraRepository;
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.boot.autoconfigure.data.cassandra.city.CityRepository;
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link CassandraRepositoriesAutoConfiguration}.
*
* @author Eddú Meléndez
*/
public class CassandraRepositoriesAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@Before
public void setUp() {
this.context = new AnnotationConfigApplicationContext();
}
@After
public void close() {
this.context.close();
}
@Test
public void testDefaultRepositoryConfiguration() {
addConfigurations(TestConfiguration.class);
assertNotNull(this.context.getBean(CityRepository.class));
assertNotNull(this.context.getBean(Cluster.class));
}
@Test
public void testNoRepositoryConfiguration() {
addConfigurations(TestExcludeConfiguration.class, EmptyConfiguration.class);
assertNotNull(this.context.getBean(Cluster.class));
}
@Test
public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
addConfigurations(TestExcludeConfiguration.class, CustomizedConfiguration.class);
assertNotNull(this.context.getBean(CityCassandraRepository.class));
}
private void addConfigurations(Class<?>... configurations) {
this.context.register(configurations);
this.context.register(CassandraAutoConfiguration.class,
CassandraRepositoriesAutoConfiguration.class,
CassandraDataAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
}
@Configuration
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
@Bean
public Session session() {
return mock(Session.class);
}
}
@Configuration
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
}
@Configuration
@TestAutoConfigurationPackage(CassandraRepositoriesAutoConfigurationTests.class)
@EnableCassandraRepositories(basePackageClasses = CityCassandraRepository.class)
static class CustomizedConfiguration {
}
@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(classes = { Session.class }, type = FilterType.ASSIGNABLE_TYPE))
static class TestExcludeConfiguration {
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra.city;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class City {
@PrimaryKey
private Long id;
@Column
private String name;
@Column
private String state;
@Column
private String country;
@Column
private String map;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
public String getMap() {
return this.map;
}
public void setMap(String map) {
this.map = map;
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.cassandra.city;
import org.springframework.data.repository.Repository;
public interface CityRepository extends Repository<City, Long> {
}

View File

@ -263,6 +263,11 @@
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
@ -2135,4 +2140,4 @@
<id>integration-test</id>
</profile>
</profiles>
</project>
</project>

View File

@ -340,6 +340,22 @@ content into your application; rather pick only the properties that you need.
# DAO ({sc-spring-boot-autoconfigure}/dao/PersistenceExceptionTranslationAutoConfiguration.{sc-ext}[PersistenceExceptionTranslationAutoConfiguration])
spring.dao.exceptiontranslation.enabled=true
# CASSANDRA ({sc-spring-boot-autoconfigure}/cassandra/CassandraProperties.{sc-ext}[CassandraProperties])
spring.data.cassandra.cluster-name= # the cluster name
spring.data.cassandra.contact-points=localhost # comma-list of cluster node addresses
spring.data.cassandra.keyspace-name= # the keyspace name
spring.data.cassandra.port= # the connection port
spring.data.cassandra.compression= # compression method (none/snappy/lz4)
spring.data.cassandra.loadbalancing-policy= # class name for a LoadBalancingPolicy
spring.data.cassandra.consistency-level= # consistency level (any/one/two/three/quorum/all...)
spring.data.cassandra.serial-consistency-level= # serial consistency level (any/one/two/three/quorum/all...)
spring.data.cassandra.fetch-size=
spring.data.cassandra.reconnection-policy= # class name for a ReconnectionPolicy
spring.data.cassandra.retry-policy= # class name for a RetryPolicy
spring.data.cassandra.connect-timeout-millis= # connect timeout (ms)
spring.data.cassandra.read-timeout-millis= # read timeout (ms)
spring.data.cassandra.ssl=false
# MONGODB ({sc-spring-boot-autoconfigure}/mongo/MongoProperties.{sc-ext}[MongoProperties])
spring.data.mongodb.host= # the db host
spring.data.mongodb.port=27017 # the connection port (defaults to 27107)

View File

@ -2460,9 +2460,9 @@ http://projects.spring.io/spring-data-redis/[Redis],
http://projects.spring.io/spring-data-gemfire/[Gemfire],
http://projects.spring.io/spring-data-couchbase/[Couchbase] and
http://projects.spring.io/spring-data-cassandra/[Cassandra].
Spring Boot provides auto-configuration for Redis, MongoDB, Elasticsearch, and Solr; you
can make use of the other projects, but you will need to configure them yourself. Refer to
the appropriate reference documentation at
Spring Boot provides auto-configuration for Redis, MongoDB, Elasticsearch, Solr and
Cassandra; you can make use of the other projects, but you will need to configure them
yourself. Refer to the appropriate reference documentation at
http://projects.spring.io/spring-data[projects.spring.io/spring-data].
@ -2781,6 +2781,63 @@ http://docs.spring.io/spring-data/elasticsearch/docs/[reference documentation].
[[boot-features-cassandra]]
=== Cassandra
http://cassandra.apache.org/[Cassandra] is an open source, distributed database management
system designed to handle large amounts of data across many commodity servers. Spring Boot
offers auto-configuration for Cassandra and abstractions on top of it provided by
https://github.com/spring-projects/spring-data-cassandra[Spring Data Cassandra].
There is a `spring-boot-starter-data-cassandra` '`Starter POM`' for collecting the
dependencies in a convenient way.
[[boot-features-connecting-to-cassandra]]
==== Connecting to Cassandra
You can inject an auto-configured `CassandraTemplate` or a Cassandra `Session`
instance as you would any other Spring Bean. The `spring.data.cassandra.*` properties
can be used to customize the connection. Generally you will to provide `keyspace-name`
and `contact-points` properties:
[source,properties,indent=0]
----
spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2
----
[source,java,indent=0]
----
@Component
public class MyBean {
private CassandraTemplate template;
@Autowired
public MyBean(CassandraTemplate template) {
this.template = template;
}
// ...
}
----
If you add a `@Bean` of your own of type `CassandraTemplate` it will replace the
default.
[[boot-features-spring-data-cassandra-repositories]]
==== Spring Data Cassandra repositories
Spring Data includes basic repository support for Cassandra. Currently this is more
limited than the JPA repositories discussed earlier, and will need to annotate finder
methods with `@Query`.
TIP: For complete details of Spring Data Cassandra, refer to their
http://docs.spring.io/spring-data/cassandra/docs/[reference documentation].
[[boot-features-caching]]
== Caching
The Spring Framework provides support for transparently adding caching to an application.

View File

@ -32,6 +32,7 @@
<module>spring-boot-sample-atmosphere</module>
<module>spring-boot-sample-batch</module>
<module>spring-boot-sample-cache</module>
<module>spring-boot-sample-data-cassandra</module>
<module>spring-boot-sample-data-elasticsearch</module>
<module>spring-boot-sample-data-gemfire</module>
<module>spring-boot-sample-data-jpa</module>

View File

@ -0,0 +1,4 @@
CREATE KEYSPACE mykeyspace WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-data-cassandra</artifactId>
<name>Spring Boot Data Cassandra Sample</name>
<description>Spring Boot Data Cassandra Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-spring</artifactId>
<version>2.1.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,49 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.cassandra;
import java.util.UUID;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.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);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.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")
public Customer findByFirstName(String firstName);
@Query("Select * from customer where lastname=?0")
public List<Customer> findByLastName(String lastName);
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.cassandra;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.datastax.driver.core.utils.UUIDs;
@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);
}
}

View File

@ -0,0 +1 @@
spring.data.cassandra.keyspace-name=mykeyspace

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.cassandra;
import org.cassandraunit.spring.CassandraDataSet;
import org.cassandraunit.spring.CassandraUnitTestExecutionListener;
import org.cassandraunit.spring.EmbeddedCassandra;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.OutputCapture;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestExecutionListeners.MergeMode;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link SampleCassandraApplication}.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(mergeMode = MergeMode.MERGE_WITH_DEFAULTS, listeners = CassandraUnitTestExecutionListener.class)
@SpringApplicationConfiguration(SampleCassandraApplication.class)
@IntegrationTest
@CassandraDataSet(keyspace = "mykeyspace", value = "setup.cql")
@EmbeddedCassandra
public class SampleCassandraApplicationTests {
@ClassRule
public static OutputCapture outputCapture = new OutputCapture();
@Test
public void testDefaultSettings() throws Exception {
String output = SampleCassandraApplicationTests.outputCapture.toString();
assertTrue("Wrong output: " + output,
output.contains("firstName='Alice', lastName='Smith'"));
}
}

View File

@ -0,0 +1,3 @@
CREATE TABLE customer (id TimeUUID PRIMARY KEY, firstname text, lastname text);
CREATE INDEX customerfistnameindex ON customer (firstname);
CREATE INDEX customersecondnameindex ON customer (lastname);

View File

@ -27,6 +27,7 @@
<module>spring-boot-starter-batch</module>
<module>spring-boot-starter-cache</module>
<module>spring-boot-starter-cloud-connectors</module>
<module>spring-boot-starter-data-cassandra</module>
<module>spring-boot-starter-data-elasticsearch</module>
<module>spring-boot-starter-data-gemfire</module>
<module>spring-boot-starter-data-jpa</module>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
<name>Spring Boot Data Cassandra Starter</name>
<description>Spring Boot Data Cassandra Starter</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
provides: spring-data-cassandra