From 4c620a83191225c48ea2949ccb3a36b640ebe070 Mon Sep 17 00:00:00 2001 From: dwebb Date: Wed, 13 Nov 2013 10:48:02 -0500 Subject: [PATCH] IN PROGRESS - issue DATACASS-32: Implement the TemplateAPI for CQL https://jira.springsource.org/browse/DATACASS-32 Completed alter table Implementation in Template --- .../core/CassandraKeyspaceFactoryBean.java | 169 +++++++------- .../cassandra/core/CassandraOperations.java | 9 + .../cassandra/core/CassandraTemplate.java | 69 +++++- .../data/cassandra/config/TestConfig.java | 38 +++- .../CassandraOperationsAlterTableTest.java | 92 ++++++++ .../template/CassandraOperationsTest.java | 206 ++++++++++-------- .../data/cassandra/test/UserAlter.java | 161 ++++++++++++++ src/test/resources/cassandra-data.yaml | 3 + 8 files changed, 557 insertions(+), 190 deletions(-) create mode 100644 src/test/java/org/springframework/data/cassandra/template/CassandraOperationsAlterTableTest.java create mode 100644 src/test/java/org/springframework/data/cassandra/test/UserAlter.java create mode 100644 src/test/resources/cassandra-data.yaml diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java b/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java index 11b63a8c1..56d9f6475 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java @@ -47,45 +47,43 @@ import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.exceptions.NoHostAvailableException; /** - * Convenient factory for configuring a Cassandra Session. - * Session is a thread safe singleton and created per a keyspace. - * So, it is enough to have one session per application. + * Convenient factory for configuring a Cassandra Session. Session is a thread safe singleton and created per a + * keyspace. So, it is enough to have one session per application. * * @author Alex Shvid */ -public class CassandraKeyspaceFactoryBean implements FactoryBean, -InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTranslator { +public class CassandraKeyspaceFactoryBean implements FactoryBean, InitializingBean, DisposableBean, + BeanClassLoaderAware, PersistenceExceptionTranslator { private static final Logger log = LoggerFactory.getLogger(CassandraKeyspaceFactoryBean.class); - + public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy"; public static final int DEFAULT_REPLICATION_FACTOR = 1; - + private ClassLoader beanClassLoader; - + private Cluster cluster; private Session session; private String keyspace; - + private CassandraConverter converter; private MappingContext, CassandraPersistentProperty> mappingContext; - + private Keyspace keyspaceBean; - + private KeyspaceAttributes keyspaceAttributes; - + private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; + + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; } - - public Keyspace getObject() throws Exception { + public Keyspace getObject() { return keyspaceBean; } - + /* * (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObjectType() @@ -101,7 +99,7 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran public boolean isSingleton() { return true; } - + /* * (non-Javadoc) * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) @@ -109,149 +107,146 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran public DataAccessException translateExceptionIfPossible(RuntimeException ex) { return exceptionTranslator.translateExceptionIfPossible(ex); } - + /* * (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { - + if (this.converter == null) { this.converter = getDefaultCassandraConverter(); } this.mappingContext = this.converter.getMappingContext(); - if (cluster == null) { - throw new IllegalArgumentException( - "at least one cluster is required"); + throw new IllegalArgumentException("at least one cluster is required"); } Session session = null; session = cluster.connect(); - + if (StringUtils.hasText(keyspace)) { - + KeyspaceMetadata keyspaceMetadata = cluster.getMetadata().getKeyspace(keyspace.toLowerCase()); boolean keyspaceExists = keyspaceMetadata != null; boolean keyspaceCreated = false; - + if (keyspaceExists) { log.info("keyspace exists " + keyspaceMetadata.asCQLQuery()); } - + if (keyspaceAttributes == null) { keyspaceAttributes = new KeyspaceAttributes(); } - + // drop the old keyspace if needed if (keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop())) { log.info("Drop keyspace " + keyspace + " on afterPropertiesSet"); session.execute("DROP KEYSPACE " + keyspace); keyspaceExists = false; - } - - // create the new keyspace if needed - if (!keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop() || keyspaceAttributes.isUpdate())) { + } + + // create the new keyspace if needed + if (!keyspaceExists + && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop() || keyspaceAttributes.isUpdate())) { + + String query = String + .format( + "CREATE KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b", + keyspace, keyspaceAttributes.getReplicationStrategy(), keyspaceAttributes.getReplicationFactor(), + keyspaceAttributes.isDurableWrites()); - String query = String.format("CREATE KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b", - keyspace, - keyspaceAttributes.getReplicationStrategy(), - keyspaceAttributes.getReplicationFactor(), - keyspaceAttributes.isDurableWrites()); - log.info("Create keyspace " + keyspace + " on afterPropertiesSet " + query); - + session.execute(query); keyspaceCreated = true; } - + // update keyspace if needed if (keyspaceAttributes.isUpdate() && !keyspaceCreated) { - + if (compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata) != null) { - - String query = String.format("ALTER KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b", - keyspace, - keyspaceAttributes.getReplicationStrategy(), - keyspaceAttributes.getReplicationFactor(), - keyspaceAttributes.isDurableWrites()); - + + String query = String + .format( + "ALTER KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b", + keyspace, keyspaceAttributes.getReplicationStrategy(), keyspaceAttributes.getReplicationFactor(), + keyspaceAttributes.isDurableWrites()); + log.info("Update keyspace " + keyspace + " on afterPropertiesSet " + query); session.execute(query); } - + } - + // validate keyspace if needed if (keyspaceAttributes.isValidate()) { - + if (!keyspaceExists) { throw new InvalidDataAccessApiUsageException("keyspace '" + keyspace + "' not found in the Cassandra"); } - + String errorField = compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata); if (errorField != null) { - throw new InvalidDataAccessApiUsageException(errorField + " attribute is not much in the keyspace '" + keyspace + "'"); + throw new InvalidDataAccessApiUsageException(errorField + " attribute is not much in the keyspace '" + + keyspace + "'"); } - + } - + session.execute("USE " + keyspace); - + if (!CollectionUtils.isEmpty(keyspaceAttributes.getTables())) { - + for (TableAttributes tableAttributes : keyspaceAttributes.getTables()) { - + String entityClassName = tableAttributes.getEntity(); Class entityClass = ClassUtils.forName(entityClassName, this.beanClassLoader); CassandraPersistentEntity entity = determineEntity(entityClass); String useTableName = tableAttributes.getName() != null ? tableAttributes.getName() : entity.getTable(); - + if (keyspaceCreated) { createNewTable(session, useTableName, entity); - } - else if (keyspaceAttributes.isUpdate()) { + } else if (keyspaceAttributes.isUpdate()) { TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase()); if (table == null) { createNewTable(session, useTableName, entity); - } - else { + } else { // alter table columns for (String cql : CQLUtils.alterTable(useTableName, entity, table)) { log.info("Execute on keyspace " + keyspace + " CQL " + cql); session.execute(cql); } } - } - else if (keyspaceAttributes.isValidate()) { + } else if (keyspaceAttributes.isValidate()) { TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase()); if (table == null) { - throw new InvalidDataAccessApiUsageException("not found table " + useTableName + " for entity " + entityClassName); + throw new InvalidDataAccessApiUsageException("not found table " + useTableName + " for entity " + + entityClassName); } // validate columns List alter = CQLUtils.alterTable(useTableName, entity, table); if (!alter.isEmpty()) { - throw new InvalidDataAccessApiUsageException("invalid table " + useTableName + " for entity " + entityClassName + ". modify it by " + alter); + throw new InvalidDataAccessApiUsageException("invalid table " + useTableName + " for entity " + + entityClassName + ". modify it by " + alter); } } - - //System.out.println("tableAttributes, entityClass=" + entityClass + ", table = " + entity.getTable()); - + + // System.out.println("tableAttributes, entityClass=" + entityClass + ", table = " + entity.getTable()); + } } - - } - + + } + // initialize property this.session = session; - + this.keyspaceBean = new Keyspace(keyspace, session, converter); } - - private void createNewTable(Session session, String useTableName, - CassandraPersistentEntity entity) + private void createNewTable(Session session, String useTableName, CassandraPersistentEntity entity) throws NoHostAvailableException { String cql = CQLUtils.createTable(useTableName, entity); log.info("Execute on keyspace " + keyspace + " CQL " + cql); @@ -261,13 +256,13 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran session.execute(indexCQL); } } - + /* * (non-Javadoc) * @see org.springframework.beans.factory.DisposableBean#destroy() */ public void destroy() throws Exception { - + if (StringUtils.hasText(keyspace) && keyspaceAttributes != null && keyspaceAttributes.isCreateDrop()) { log.info("Drop keyspace " + keyspace + " on destroy"); session.execute("USE system"); @@ -287,12 +282,13 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran public void setKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes) { this.keyspaceAttributes = keyspaceAttributes; } - + public void setConverter(CassandraConverter converter) { this.converter = converter; } - private static String compareKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes, KeyspaceMetadata keyspaceMetadata) { + private static String compareKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes, + KeyspaceMetadata keyspaceMetadata) { if (keyspaceAttributes.isDurableWrites() != keyspaceMetadata.isDurableWrites()) { return "durableWrites"; } @@ -306,11 +302,10 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran if (keyspaceAttributes.getReplicationFactor() != replicationFactor) { return "replication_factor"; } - } - catch(NumberFormatException e) { + } catch (NumberFormatException e) { return "replication_factor"; } - + String attributesStrategy = keyspaceAttributes.getReplicationStrategy(); if (attributesStrategy.indexOf('.') == -1) { attributesStrategy = "org.apache.cassandra.locator." + attributesStrategy; @@ -321,7 +316,7 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran } return null; } - + CassandraPersistentEntity determineEntity(Class entityClass) { if (entityClass == null) { @@ -336,7 +331,7 @@ InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTran } return entity; } - + private static final CassandraConverter getDefaultCassandraConverter() { MappingCassandraConverter converter = new MappingCassandraConverter(new CassandraMappingContext()); converter.afterPropertiesSet(); diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java b/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java index 6200e107e..e11e7a79d 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java @@ -22,6 +22,7 @@ import org.springframework.data.cassandra.dto.RingMember; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; +import com.datastax.driver.core.TableMetadata; /** * @author Alex Shvid @@ -43,6 +44,14 @@ public interface CassandraOperations { */ String getTableName(Class entityClass); + /** + * Get the metatdata for the given entityClass table mapping + * + * @param entityClass + * @return The table metadata + */ + TableMetadata getTableMetadata(Class entityClass, final String tableName); + /** * Execute query and return Cassandra ResultSet * diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index d85b657ee..d7e99e737 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -47,6 +47,7 @@ import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; import com.datastax.driver.core.Row; import com.datastax.driver.core.Session; +import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.exceptions.NoHostAvailableException; /** @@ -531,8 +532,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void alterTable(Class entityClass) { - // TODO Auto-generated method stub - + alterTable(entityClass, getTableName(entityClass)); } /* (non-Javadoc) @@ -540,7 +540,40 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void alterTable(Class entityClass, String tableName) { - // TODO Auto-generated method stub + + doAlterTable(entityClass, tableName); + + } + + /** + * Create a list of query operations to alter the table for the given entity + * + * @param entityClass + * @param tableName + */ + protected void doAlterTable(Class entityClass, String tableName) { + + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + + Assert.notNull(entity); + + final TableMetadata tableMetadata = getTableMetadata(entityClass, tableName); + + final List queryList = CQLUtils.alterTable(tableName, entity, tableMetadata); + + execute(new SessionCallback() { + + public Object doInSession(Session s) throws DataAccessException { + + for (String q : queryList) { + log.info(q); + s.execute(q); + } + + return null; + + } + }); } @@ -562,4 +595,34 @@ public class CassandraTemplate implements CassandraOperations { } + /* (non-Javadoc) + * @see org.springframework.data.cassandra.core.CassandraOperations#getTableMetadata(java.lang.Class) + */ + @Override + public TableMetadata getTableMetadata(Class entityClass, String tableName) { + + /* + * Determine the table name if not provided + */ + if (tableName == null) { + tableName = getTableName(entityClass); + } + + Assert.notNull(tableName); + + final String metadataTableName = tableName; + + return execute(new SessionCallback() { + + public TableMetadata doInSession(Session s) throws DataAccessException { + + log.info("Keyspace => " + keyspace.getKeyspace()); + + return s.getCluster().getMetadata().getKeyspace(keyspace.getKeyspace()).getTable(metadataTableName); + + } + + }); + + } } diff --git a/src/test/java/org/springframework/data/cassandra/config/TestConfig.java b/src/test/java/org/springframework/data/cassandra/config/TestConfig.java index 5c526ed60..cb2f23829 100644 --- a/src/test/java/org/springframework/data/cassandra/config/TestConfig.java +++ b/src/test/java/org/springframework/data/cassandra/config/TestConfig.java @@ -2,6 +2,8 @@ package org.springframework.data.cassandra.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.CassandraKeyspaceFactoryBean; +import org.springframework.data.cassandra.core.CassandraTemplate; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Cluster.Builder; @@ -10,17 +12,17 @@ import com.datastax.driver.core.Cluster.Builder; * Setup any spring configuration for unit tests * * @author David Webb - * + * */ @Configuration public class TestConfig extends AbstractCassandraConfiguration { - + /* (non-Javadoc) * @see org.springframework.data.cassandra.config.AbstractCassandraConfiguration#getKeyspaceName() */ @Override protected String getKeyspaceName() { - return null; + return "test"; } /* (non-Javadoc) @@ -28,13 +30,33 @@ public class TestConfig extends AbstractCassandraConfiguration { */ @Override @Bean - public Cluster cluster() throws Exception { - + public Cluster cluster() { + Builder builder = Cluster.builder(); - + builder.addContactPoint("127.0.0.1"); - + return builder.build(); } - + + @Bean + public CassandraKeyspaceFactoryBean keyspaceFactoryBean() { + + CassandraKeyspaceFactoryBean bean = new CassandraKeyspaceFactoryBean(); + bean.setCluster(cluster()); + bean.setKeyspace("test"); + + return bean; + + } + + @Bean + public CassandraTemplate cassandraTemplate() { + + CassandraTemplate template = new CassandraTemplate(keyspaceFactoryBean().getObject()); + + return template; + + } + } diff --git a/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsAlterTableTest.java b/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsAlterTableTest.java new file mode 100644 index 000000000..6dd3d4916 --- /dev/null +++ b/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsAlterTableTest.java @@ -0,0 +1,92 @@ +/** + * All BrightMove Code is Copyright 2004-2013 BrightMove Inc. + * Modification of code without the express written consent of + * BrightMove, Inc. is strictly forbidden. + * + * Author: David Webb (dwebb@brightmove.com) + * Created On: Nov 11, 2013 + */ +package org.springframework.data.cassandra.template; + +import java.io.IOException; + +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.thrift.transport.TTransportException; +import org.cassandraunit.DataLoader; +import org.cassandraunit.dataset.yaml.ClassPathYamlDataSet; +import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.data.cassandra.config.TestConfig; +import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.data.cassandra.test.User; +import org.springframework.data.cassandra.test.UserAlter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +/** + * @author David Webb (dwebb@brightmove.com) + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class) +public class CassandraOperationsAlterTableTest { + + @Autowired + private CassandraTemplate cassandraTemplate; + + @Mock + ApplicationContext context; + + private static Logger log = LoggerFactory.getLogger(CassandraOperationsAlterTableTest.class); + + @BeforeClass + public static void startCassandra() throws IOException, TTransportException, ConfigurationException, + InterruptedException { + EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml"); + + /* + * Load data file to creat the test keyspace before we init the template + */ + DataLoader dataLoader = new DataLoader("Test Cluster", "localhost:9160"); + dataLoader.load(new ClassPathYamlDataSet("cassandra-data.yaml")); + + } + + @Before + public void setupKeyspace() { + cassandraTemplate.executeQuery("use test;"); + + log.info("Creating Table..."); + + cassandraTemplate.createTable(User.class); + + } + + @Test + public void alterTableTest() { + + cassandraTemplate.alterTable(UserAlter.class); + + } + + @After + public void clearCassandra() { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + } + + @AfterClass + public static void stopCassandra() { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + } +} diff --git a/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsTest.java b/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsTest.java index 5ca565913..e1964e13a 100644 --- a/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsTest.java +++ b/src/test/java/org/springframework/data/cassandra/template/CassandraOperationsTest.java @@ -11,12 +11,15 @@ package org.springframework.data.cassandra.template; import static org.junit.Assert.assertNotNull; import java.io.IOException; +import java.util.Date; import java.util.List; import junit.framework.Assert; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.thrift.transport.TTransportException; +import org.cassandraunit.DataLoader; +import org.cassandraunit.dataset.yaml.ClassPathYamlDataSet; import org.cassandraunit.utils.EmbeddedCassandraServerHelper; import org.junit.After; import org.junit.AfterClass; @@ -29,8 +32,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.cassandra.config.TestConfig; import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.data.cassandra.dto.RingMember; +import org.springframework.data.cassandra.test.LogEntry; import org.springframework.data.cassandra.test.User; -import org.springframework.data.cassandra.vo.RingMember; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; @@ -39,111 +43,129 @@ import com.datastax.driver.core.Session; /** * @author David Webb (dwebb@brightmove.com) - * + * */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration (classes = {TestConfig.class}, loader = AnnotationConfigContextLoader.class) +@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class) public class CassandraOperationsTest { - + @Autowired private CassandraTemplate cassandraTemplate; - + private static Logger log = LoggerFactory.getLogger(CassandraOperationsTest.class); - - protected Session session; - - @BeforeClass - public static void startCassandra() - throws IOException, TTransportException, ConfigurationException, InterruptedException { - EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml"); - } - - @Before - public void setupKeyspace() { - - log.info("Creating Keyspace..."); - - cassandraTemplate.executeQuery("CREATE KEYSPACE test WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"); - log.info("Using Keyspace..."); + protected Session session; - cassandraTemplate.executeQuery("use test;"); + @BeforeClass + public static void startCassandra() throws IOException, TTransportException, ConfigurationException, + InterruptedException { + EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml"); - log.info("Creating Table..."); - - cassandraTemplate.createTable(User.class); - - - } - - @Test - public void ringTest() { - - List ring = cassandraTemplate.describeRing(); - /* - * There must be 1 node in the cluster if the embedded server is running. + * Load data file to creat the test keyspace before we init the template + */ + DataLoader dataLoader = new DataLoader("Test Cluster", "localhost:9160"); + dataLoader.load(new ClassPathYamlDataSet("cassandra-data.yaml")); + + } + + @Before + public void setupKeyspace() { + + /* + * Load data file to creat the test keyspace before we init the template + */ + DataLoader dataLoader = new DataLoader("Test Cluster", "localhost:9160"); + dataLoader.load(new ClassPathYamlDataSet("cassandra-data.yaml")); + + log.info("Creating Table..."); + + cassandraTemplate.createTable(User.class); + + cassandraTemplate.createTable(LogEntry.class); + + } + + @Test + public void ringTest() { + + List ring = cassandraTemplate.describeRing(); + + /* + * There must be 1 node in the cluster if the embedded server is + * running. */ assertNotNull(ring); - - for (RingMember h: ring) { + + for (RingMember h : ring) { log.info(h.address); } - } - - /** - * This test inserts and selects users from the test.users table - * This is testing the CassandraTemplate: - *
    - *
  • insert()
  • - *
  • selectOne()
  • - *
  • select()
  • - *
  • remove()
  • - *
- */ - @Test - public void UsersTest() { - - User u = new User(); - u.setUsername("cassandra"); - u.setFirstName("Apache"); - u.setLastName("Cassnadra"); - u.setAge(40); - - cassandraTemplate.insert(u, "users"); - - User us = cassandraTemplate.selectOne("select * from test.users where username='cassandra';" , User.class); - - log.debug("Output from select One"); - log.debug(us.getFirstName()); - log.debug(us.getLastName()); - - List users = cassandraTemplate.select("Select * from test.users", User.class); + } - log.debug("Output from select All"); - for (User x: users) { - log.debug(x.getFirstName()); - log.debug(x.getLastName()); - } - - cassandraTemplate.remove(u); - - User delUser = cassandraTemplate.selectOne("select * from test.users where username='cassandra';" , User.class); - - log.info("delUser => " + delUser); - - Assert.assertNull(delUser); - - - } - - @After - public void clearCassandra() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - } + /** + * This test inserts and selects users from the test.users table This is testing the CassandraTemplate: + *
    + *
  • insert()
  • + *
  • selectOne()
  • + *
  • select()
  • + *
  • remove()
  • + *
+ */ + @Test + public void UsersTest() { - @AfterClass - public static void stopCassandra() { - EmbeddedCassandraServerHelper.stopEmbeddedCassandra(); - } + User u = new User(); + u.setUsername("cassandra"); + u.setFirstName("Apache"); + u.setLastName("Cassnadra"); + u.setAge(40); + + cassandraTemplate.insert(u, "users"); + + User us = cassandraTemplate.selectOne("select * from test.users where username='cassandra';", User.class); + + log.debug("Output from select One"); + log.debug(us.getFirstName()); + log.debug(us.getLastName()); + + List users = cassandraTemplate.select("Select * from test.users", User.class); + + log.debug("Output from select All"); + for (User x : users) { + log.debug(x.getFirstName()); + log.debug(x.getLastName()); + } + + cassandraTemplate.remove(u); + + User delUser = cassandraTemplate.selectOne("select * from test.users where username='cassandra';", User.class); + + log.info("delUser => " + delUser); + + Assert.assertNull(delUser); + + } + + // @Test + public void multiplePKTest() { + + LogEntry l = new LogEntry(); + l.setLogDate(new Date()); + l.setHostname("localhost"); + l.setLogData("Host is Up"); + + cassandraTemplate.insert(l); + + } + + @After + public void clearCassandra() { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + + } + + @AfterClass + public static void stopCassandra() { + EmbeddedCassandraServerHelper.stopEmbeddedCassandra(); + } } diff --git a/src/test/java/org/springframework/data/cassandra/test/UserAlter.java b/src/test/java/org/springframework/data/cassandra/test/UserAlter.java new file mode 100644 index 000000000..900df065f --- /dev/null +++ b/src/test/java/org/springframework/data/cassandra/test/UserAlter.java @@ -0,0 +1,161 @@ +/* + * Copyright 2010-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 org.springframework.data.cassandra.test; + +import java.util.Set; + +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.mapping.Index; +import org.springframework.data.cassandra.mapping.Table; + +/** + * This is an example of the Users statis table, where all fields are columns in Cassandra row. Some fields can be + * Set,List,Map like emails. + * + * User contains base information related for separate user, like names, additional information, emails, following + * users, friends. + * + * @author Alex Shvid + */ +@Table(name = "users") +public class UserAlter { + + /* + * Primary Row ID + */ + @Id + private String username; + + /* + * Public information + */ + private String firstName; + private String lastName; + + /* + * Secondary index, used only on fields with common information, + * not effective on email, username + */ + @Index + private String place; + + private String nickName; + + /* + * Password + */ + private String password; + + /* + * Age + */ + private int age; + + /* + * Following other users in userline + */ + private Set following; + + /* + * Friends of the user + */ + private Set friends; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getPlace() { + return place; + } + + public void setPlace(String place) { + this.place = place; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Set getFollowing() { + return following; + } + + public void setFollowing(Set following) { + this.following = following; + } + + public Set getFriends() { + return friends; + } + + public void setFriends(Set friends) { + this.friends = friends; + } + + /** + * @return Returns the age. + */ + public int getAge() { + return age; + } + + /** + * @param age The age to set. + */ + public void setAge(int age) { + this.age = age; + } + + /** + * @return Returns the nickName. + */ + public String getNickName() { + return nickName; + } + + /** + * @param nickName The nickName to set. + */ + public void setNickName(String nickName) { + this.nickName = nickName; + } + +} diff --git a/src/test/resources/cassandra-data.yaml b/src/test/resources/cassandra-data.yaml new file mode 100644 index 000000000..a0e13da6e --- /dev/null +++ b/src/test/resources/cassandra-data.yaml @@ -0,0 +1,3 @@ +name: test +replicationFactor: 1 +strategy: org.apache.cassandra.locator.SimpleStrategy \ No newline at end of file