├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── example │ │ ├── CassandraConfiguration.java │ │ └── domain │ │ ├── Event.java │ │ └── EventRepository.java └── resources │ ├── cassandra.properties │ └── logback.xml └── test └── java └── example ├── BaseIntegrationTest.java ├── CassandraTemplateIntegrationTest.java ├── CqlTemplateIntegrationTest.java └── EventRepositoryIntegrationTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | ## Eclipse (we include .project etc as we will want these for installation of labs) 2 | .metadata 3 | bin/ 4 | tmp/ 5 | target/ 6 | *.tmp 7 | *.bak 8 | *.swp 9 | *~.nib 10 | local.properties 11 | 12 | # External tool builders 13 | .externalToolBuilders/ 14 | 15 | # Locally stored "Eclipse launch configurations" 16 | *.launch 17 | 18 | ## IntelliJ 19 | *.iml 20 | *.ipr 21 | *.iws 22 | .idea/ 23 | out/ 24 | target/ 25 | 26 | # Folder config file 27 | Desktop.ini 28 | 29 | ## Mac 30 | .DS_Store 31 | 32 | # Eclipse Project artifacts 33 | .classpath 34 | .settings 35 | .project 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 OpenCredo Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | spring-data-cassandra-example 2 | ============================= 3 | This repository contains the source code for [Spring Data Cassandra Overview](http://www.opencredo.com/spring-data-cassandra-overview/) article published on [OpenCredo](http://www.opencredo.com/) blog. 4 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | example 8 | spring-data-cassandra-example 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.apache.maven.plugins 15 | maven-compiler-plugin 16 | 3.5.1 17 | 18 | 1.7 19 | 1.7 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.data 28 | spring-data-cassandra 29 | 1.1.0.RELEASE 30 | 31 | 32 | ch.qos.logback 33 | logback-classic 34 | 1.1.2 35 | 36 | 37 | junit 38 | junit 39 | 4.11 40 | test 41 | 42 | 43 | org.springframework 44 | spring-test 45 | 4.0.7.RELEASE 46 | test 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/example/CassandraConfiguration.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.PropertySource; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; 11 | import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration; 12 | import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext; 13 | import org.springframework.data.cassandra.mapping.CassandraMappingContext; 14 | import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; 15 | 16 | @Configuration 17 | @PropertySource(value = { "classpath:cassandra.properties" }) 18 | @EnableCassandraRepositories(basePackages = { "example" }) 19 | public class CassandraConfiguration extends AbstractCassandraConfiguration { 20 | 21 | private static final Logger LOG = LoggerFactory.getLogger(CassandraConfiguration.class); 22 | 23 | @Autowired 24 | private Environment environment; 25 | 26 | @Bean 27 | public CassandraClusterFactoryBean cluster() { 28 | CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); 29 | cluster.setContactPoints(environment.getProperty("cassandra.contactpoints")); 30 | cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port"))); 31 | return cluster; 32 | } 33 | 34 | @Override 35 | protected String getKeyspaceName() { 36 | return environment.getProperty("cassandra.keyspace"); 37 | } 38 | 39 | @Bean 40 | public CassandraMappingContext cassandraMapping() throws ClassNotFoundException { 41 | return new BasicCassandraMappingContext(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/example/domain/Event.java: -------------------------------------------------------------------------------- 1 | package example.domain; 2 | 3 | import org.springframework.cassandra.core.Ordering; 4 | import org.springframework.cassandra.core.PrimaryKeyType; 5 | import org.springframework.data.cassandra.mapping.Column; 6 | import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; 7 | import org.springframework.data.cassandra.mapping.Table; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | import java.util.UUID; 12 | 13 | @Table 14 | public class Event { 15 | 16 | @PrimaryKeyColumn(name = "id", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING) 17 | private final UUID id; 18 | 19 | @PrimaryKeyColumn(name = "type", ordinal = 0, type = PrimaryKeyType.PARTITIONED) 20 | private final String type; 21 | 22 | @PrimaryKeyColumn(name = "bucket", ordinal = 1, type = PrimaryKeyType.PARTITIONED) 23 | private final String bucket; 24 | 25 | @Column 26 | private final Set tags = new HashSet<>(); 27 | 28 | public Event(UUID id, String type, String bucket, Set tags) { 29 | this.id = id; 30 | this.type = type; 31 | this.bucket = bucket; 32 | this.tags.addAll(tags); 33 | } 34 | 35 | public UUID getId() { 36 | return id; 37 | } 38 | 39 | public String getType() { 40 | return type; 41 | } 42 | 43 | public String getBucket() { 44 | return bucket; 45 | } 46 | 47 | public Set getTags() { 48 | return tags; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "Event{" + "id=" + id + ", type=" + type + ", bucket=" + bucket + ", tags=" + tags + '}'; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | 61 | Event event = (Event) o; 62 | 63 | if (!bucket.equals(event.bucket)) return false; 64 | if (!id.equals(event.id)) return false; 65 | if (!tags.equals(event.tags)) return false; 66 | if (!type.equals(event.type)) return false; 67 | 68 | return true; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | int result = id.hashCode(); 74 | result = 31 * result + type.hashCode(); 75 | result = 31 * result + bucket.hashCode(); 76 | result = 31 * result + tags.hashCode(); 77 | return result; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/example/domain/EventRepository.java: -------------------------------------------------------------------------------- 1 | package example.domain; 2 | 3 | import org.springframework.data.cassandra.repository.CassandraRepository; 4 | import org.springframework.data.cassandra.repository.Query; 5 | 6 | public interface EventRepository extends CassandraRepository { 7 | 8 | @Query("select * from event where type = ?0 and bucket=?1") 9 | Iterable findByTypeAndBucket(String type, String bucket); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/cassandra.properties: -------------------------------------------------------------------------------- 1 | cassandra.contactpoints=127.0.0.1 2 | cassandra.port=9042 3 | cassandra.keyspace=events -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %-50logger{50} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/java/example/BaseIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import example.domain.Event; 4 | import org.junit.Before; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cassandra.core.cql.CqlIdentifier; 8 | import org.springframework.data.cassandra.core.CassandraAdminOperations; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import java.util.HashMap; 13 | 14 | @RunWith(SpringJUnit4ClassRunner.class) 15 | @ContextConfiguration(classes = CassandraConfiguration.class) 16 | public abstract class BaseIntegrationTest { 17 | 18 | @Autowired 19 | private CassandraAdminOperations adminTemplate; 20 | 21 | @Before 22 | public void resetKeySpace() { 23 | adminTemplate.dropTable(CqlIdentifier.cqlId("event")); 24 | adminTemplate.createTable(true, CqlIdentifier.cqlId("event"), Event.class, new HashMap()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/example/CassandraTemplateIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import com.datastax.driver.core.querybuilder.QueryBuilder; 4 | import com.datastax.driver.core.querybuilder.Select; 5 | import com.datastax.driver.core.utils.UUIDs; 6 | import com.google.common.collect.ImmutableSet; 7 | import example.domain.Event; 8 | import org.hamcrest.core.IsEqual; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.cassandra.core.CassandraOperations; 12 | 13 | import java.util.List; 14 | 15 | import static org.hamcrest.CoreMatchers.hasItem; 16 | import static org.hamcrest.CoreMatchers.is; 17 | import static org.junit.Assert.assertThat; 18 | 19 | public class CassandraTemplateIntegrationTest extends BaseIntegrationTest { 20 | 21 | public static final String TIME_BUCKET = "2014-01-01"; 22 | 23 | @Autowired 24 | private CassandraOperations cassandraTemplate; 25 | 26 | @Test 27 | public void supportsPojoToCqlMappings() { 28 | Event event = new Event(UUIDs.timeBased(), "type1", TIME_BUCKET, ImmutableSet.of("tag1", "tag3")); 29 | cassandraTemplate.insert(event); 30 | 31 | Select select = QueryBuilder.select().from("event").where(QueryBuilder.eq("type", "type1")).and(QueryBuilder.eq("bucket", TIME_BUCKET)).limit(10); 32 | 33 | Event retrievedEvent = cassandraTemplate.selectOne(select, Event.class); 34 | 35 | assertThat(retrievedEvent, IsEqual.equalTo(event)); 36 | 37 | List retrievedEvents = cassandraTemplate.select(select, Event.class); 38 | 39 | assertThat(retrievedEvents.size(), is(1)); 40 | assertThat(retrievedEvents, hasItem(event)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/example/CqlTemplateIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import com.datastax.driver.core.PreparedStatement; 4 | import com.datastax.driver.core.ResultSet; 5 | import com.datastax.driver.core.Statement; 6 | import com.datastax.driver.core.querybuilder.Insert; 7 | import com.datastax.driver.core.querybuilder.QueryBuilder; 8 | import com.datastax.driver.core.querybuilder.Select; 9 | import com.datastax.driver.core.utils.UUIDs; 10 | import com.google.common.collect.ImmutableSet; 11 | import org.hamcrest.core.Is; 12 | import org.junit.Test; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.cassandra.core.CqlOperations; 15 | 16 | import static org.junit.Assert.assertThat; 17 | 18 | public class CqlTemplateIntegrationTest extends BaseIntegrationTest { 19 | 20 | public static final String TIME_BUCKET = "2014-01-01"; 21 | 22 | @Autowired 23 | private CqlOperations cqlTemplate; 24 | 25 | @Test 26 | public void allowsExecutingCqlStatements() { 27 | insertEventUsingCqlString(); 28 | insertEventUsingStatementBuildWithQueryBuilder(); 29 | insertEventUsingPreparedStatement(); 30 | 31 | ResultSet resultSet1 = cqlTemplate.query("select * from event where type='type2' and bucket='" + TIME_BUCKET + "'"); 32 | 33 | assertThat(resultSet1.all().size(), Is.is(2)); 34 | 35 | Select select = QueryBuilder.select().from("event").where(QueryBuilder.eq("type", "type1")).and(QueryBuilder.eq("bucket", TIME_BUCKET)).limit(10); 36 | ResultSet resultSet2 = cqlTemplate.query(select); 37 | 38 | assertThat(resultSet2.all().size(), Is.is(1)); 39 | } 40 | 41 | private void insertEventUsingCqlString() { 42 | cqlTemplate.execute("insert into event (id, type, bucket, tags) values (" + UUIDs.timeBased() + ", 'type1', '" + TIME_BUCKET + "', {'tag2', 'tag3'})"); 43 | } 44 | 45 | private void insertEventUsingStatementBuildWithQueryBuilder() { 46 | Insert insertStatement = QueryBuilder.insertInto("event").value("id", UUIDs.timeBased()).value("type", "type2") 47 | .value("bucket", TIME_BUCKET).value("tags", ImmutableSet.of("tag1")); 48 | cqlTemplate.execute(insertStatement); 49 | } 50 | 51 | private void insertEventUsingPreparedStatement() { 52 | PreparedStatement preparedStatement = cqlTemplate.getSession().prepare("insert into event (id, type, bucket, tags) values (?, ?, ?, ?)"); 53 | Statement insertStatement = preparedStatement.bind(UUIDs.timeBased(), "type2", TIME_BUCKET, ImmutableSet.of("tag1", "tag2")); 54 | cqlTemplate.execute(insertStatement); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/example/EventRepositoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import com.datastax.driver.core.utils.UUIDs; 4 | import com.google.common.collect.ImmutableSet; 5 | import example.domain.Event; 6 | import example.domain.EventRepository; 7 | import org.junit.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import static org.hamcrest.CoreMatchers.hasItem; 11 | import static org.hamcrest.CoreMatchers.not; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class EventRepositoryIntegrationTest extends BaseIntegrationTest { 15 | 16 | public static final String TIME_BUCKET = "2014-01-01"; 17 | 18 | @Autowired 19 | private EventRepository eventRepository; 20 | 21 | @Test 22 | public void repositoryStoresAndRetrievesEvents() { 23 | Event event1 = new Event(UUIDs.timeBased(), "type1", TIME_BUCKET, ImmutableSet.of("tag1", "tag2")); 24 | Event event2 = new Event(UUIDs.timeBased(), "type1", TIME_BUCKET, ImmutableSet.of("tag3")); 25 | eventRepository.save(ImmutableSet.of(event1, event2)); 26 | 27 | Iterable events = eventRepository.findByTypeAndBucket("type1", TIME_BUCKET); 28 | 29 | assertThat(events, hasItem(event1)); 30 | assertThat(events, hasItem(event2)); 31 | } 32 | 33 | @Test 34 | public void repositoryDeletesStoredEvents() { 35 | Event event1 = new Event(UUIDs.timeBased(), "type1", TIME_BUCKET, ImmutableSet.of("tag1", "tag2")); 36 | Event event2 = new Event(UUIDs.timeBased(), "type1", TIME_BUCKET, ImmutableSet.of("tag3")); 37 | eventRepository.save(ImmutableSet.of(event1, event2)); 38 | 39 | eventRepository.delete(event1); 40 | eventRepository.delete(event2); 41 | 42 | Iterable events = eventRepository.findByTypeAndBucket("type1", TIME_BUCKET); 43 | 44 | assertThat(events, not(hasItem(event1))); 45 | assertThat(events, not(hasItem(event2))); 46 | } 47 | } 48 | --------------------------------------------------------------------------------