IN PROGRESS - issue DATACASS-32: Implement the TemplateAPI for CQL
https://jira.springsource.org/browse/DATACASS-32 Completed alter table Implementation in Template
This commit is contained in:
@@ -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<Keyspace>,
|
||||
InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTranslator {
|
||||
public class CassandraKeyspaceFactoryBean implements FactoryBean<Keyspace>, 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<? extends CassandraPersistentEntity<?>, 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<String> 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();
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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<String> queryList = CQLUtils.alterTable(tableName, entity, tableMetadata);
|
||||
|
||||
execute(new SessionCallback<Object>() {
|
||||
|
||||
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<TableMetadata>() {
|
||||
|
||||
public TableMetadata doInSession(Session s) throws DataAccessException {
|
||||
|
||||
log.info("Keyspace => " + keyspace.getKeyspace());
|
||||
|
||||
return s.getCluster().getMetadata().getKeyspace(keyspace.getKeyspace()).getTable(metadataTableName);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<RingMember> 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<RingMember> 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:
|
||||
* <ul>
|
||||
* <li>insert()</li>
|
||||
* <li>selectOne()</li>
|
||||
* <li>select()</li>
|
||||
* <li>remove()</li>
|
||||
* </ul>
|
||||
*/
|
||||
@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<User> 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:
|
||||
* <ul>
|
||||
* <li>insert()</li>
|
||||
* <li>selectOne()</li>
|
||||
* <li>select()</li>
|
||||
* <li>remove()</li>
|
||||
* </ul>
|
||||
*/
|
||||
@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<User> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> following;
|
||||
|
||||
/*
|
||||
* Friends of the user
|
||||
*/
|
||||
private Set<String> 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<String> getFollowing() {
|
||||
return following;
|
||||
}
|
||||
|
||||
public void setFollowing(Set<String> following) {
|
||||
this.following = following;
|
||||
}
|
||||
|
||||
public Set<String> getFriends() {
|
||||
return friends;
|
||||
}
|
||||
|
||||
public void setFriends(Set<String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
3
src/test/resources/cassandra-data.yaml
Normal file
3
src/test/resources/cassandra-data.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
name: test
|
||||
replicationFactor: 1
|
||||
strategy: org.apache.cassandra.locator.SimpleStrategy
|
||||
Reference in New Issue
Block a user