This commit is contained in:
Alex Shvid
2013-11-27 15:13:09 -08:00
20 changed files with 1228 additions and 26 deletions

View File

@@ -64,6 +64,7 @@
<name>Alex Shvid</name>
<email>a at shvid.com</email>
<roles>
<role>Project Lead</role>
<role>Developer</role>
</roles>
<timezone>-8</timezone>

View File

@@ -28,7 +28,7 @@ import com.datastax.driver.core.TableMetadata;
*/
public class CassandraAdminTemplate implements CassandraAdminOperations {
private static Logger log = LoggerFactory.getLogger(CassandraAdminTemplate.class);
private static final Logger log = LoggerFactory.getLogger(CassandraAdminTemplate.class);
private SpringDataKeyspace keyspace;
private Session session;

View File

@@ -50,6 +50,16 @@ public interface CassandraDataOperations {
*/
<T> List<T> select(String cql, Class<T> selectClass);
/**
* Execute query and convert ResultSet to the list of entities
*
* @param selectQuery must not be {@literal null}.
* @param selectClass must not be {@literal null}, mapped entity type.
* @return
*/
<T> List<T> select(Select selectQuery, Class<T> selectClass);
/**
* Execute query and convert ResultSet to the entity
*
@@ -59,12 +69,26 @@ public interface CassandraDataOperations {
*/
<T> T selectOne(String cql, Class<T> selectClass);
<T> List<T> select(Select selectQuery, Class<T> selectClass);
<T> T selectOne(Select selectQuery, Class<T> selectClass);
/**
* Counts rows for given query
*
* @param selectQuery
* @return
*/
Long count(Select selectQuery);
/**
* Counts all rows for given table
*
* @param tableName
* @return
*/
Long count(String tableName);
/**
* Insert the given object to the table by id.
*

View File

@@ -18,7 +18,6 @@ package org.springframework.data.cassandra.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -43,6 +42,7 @@ import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.Batch;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
/**
@@ -123,13 +123,22 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectCount(com.datastax.driver.core.querybuilder.Select)
* @see org.springframework.data.cassandra.core.CassandraOperations#count(com.datastax.driver.core.querybuilder.Select)
*/
@Override
public Long count(Select selectQuery) {
return doSelectCount(selectQuery);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#count(java.lang.String)
*/
@Override
public Long count(String tableName) {
Select select = QueryBuilder.select().countAll().from(tableName);
return doSelectCount(select);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(java.util.List)
*/
@@ -165,7 +174,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> void delete(List<T> entities, String tableName) {
delete(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
delete(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -223,7 +233,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> void delete(T entity, String tableName) {
delete(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
delete(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -280,7 +291,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> void deleteAsynchronously(List<T> entities, String tableName) {
insertAsynchronously(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
insertAsynchronously(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -338,7 +350,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> void deleteAsynchronously(T entity, String tableName) {
deleteAsynchronously(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
deleteAsynchronously(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -430,7 +443,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> List<T> insert(List<T> entities, String tableName) {
return insert(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return insert(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -488,7 +502,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> T insert(T entity, String tableName) {
return insert(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return insert(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -545,7 +560,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> List<T> insertAsynchronously(List<T> entities, String tableName) {
return insertAsynchronously(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return insertAsynchronously(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -603,7 +619,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> T insertAsynchronously(T entity, String tableName) {
return insertAsynchronously(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return insertAsynchronously(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -695,7 +712,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> List<T> update(List<T> entities, String tableName) {
return update(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return update(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -753,7 +771,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> T update(T entity, String tableName) {
return update(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return update(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -810,7 +829,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> List<T> updateAsynchronously(List<T> entities, String tableName) {
return updateAsynchronously(entities, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return updateAsynchronously(entities, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -868,7 +888,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
@Override
public <T> T updateAsynchronously(T entity, String tableName) {
return updateAsynchronously(entity, tableName, new HashMap<String, Object>());
Map<String, Object> defaultOptions = Collections.emptyMap();
return updateAsynchronously(entity, tableName, defaultOptions);
}
/* (non-Javadoc)
@@ -968,6 +989,8 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
*/
private <T> T doSelectOne(final String query, ReadRowCallback<T> readRowCallback) {
logger.info(query);
/*
* Run the Query
*/
@@ -1183,6 +1206,7 @@ public class CassandraDataTemplate extends CassandraTemplate implements Cassandr
try {
final Query q = CqlUtils.toInsertQuery(keyspace, tableName, entity, optionsByName, cassandraConverter);
logger.info(q.toString());
if (q.getConsistencyLevel() != null) {
logger.info(q.getConsistencyLevel().name());

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2012 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.repository.config;
import java.lang.annotation.Annotation;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} to setup Cassandra repositories via {@link EnableCassandraRepositories}.
*
* @author Alex Shvid
*
*/
public class CassandraRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.config.
* RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
*/
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableCassandraRepositories.class;
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.config.
* RepositoryBeanDefinitionRegistrarSupport#getExtension()
*/
@Override
protected RepositoryConfigurationExtension getExtension() {
return new CassandraRepositoryConfigurationExtension();
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2012 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.repository.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* {@link RepositoryConfigurationExtension} for Cassandra.
*
* @author Alex Shvid
*
*/
public class CassandraRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
private static final String CASSANDRA_DATA_TEMPLATE_REF = "cassandra-data-template-ref";
private static final String CREATE_QUERY_INDEXES = "create-query-indexes";
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix()
*/
@Override
protected String getModulePrefix() {
return "cassandra";
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getRepositoryFactoryClassName()
*/
public String getRepositoryFactoryClassName() {
return CassandraRepositoryFactoryBean.class.getName();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {
Element element = config.getElement();
ParsingUtils.setPropertyReference(builder, element, CASSANDRA_DATA_TEMPLATE_REF, "cassandraDataTemplate");
ParsingUtils.setPropertyValue(builder, element, CREATE_QUERY_INDEXES, "createIndexesForQueryMethods");
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) {
AnnotationAttributes attributes = config.getAttributes();
String cassandraDataTemplateRef = attributes.getString("cassandraDataTemplateRef");
if (StringUtils.hasText(cassandraDataTemplateRef)) {
builder.addPropertyReference("cassandraDataTemplate", cassandraDataTemplateRef);
}
builder.addPropertyValue("createIndexesForQueryMethods", attributes.getBoolean("createIndexesForQueryMethods"));
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2012 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.repository.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.cassandra.core.CassandraDataTemplate;
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
/**
* Annotation to enable Cassandra repositories.
*
* @author Alex Shvid
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(CassandraRepositoriesRegistrar.class)
public @interface EnableCassandraRepositories {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableCassandraRepositories("org.my.pkg")} instead of
* {@code @EnableCassandraRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code UserRepository} the corresponding implementation class will be looked up scanning for
* {@code UserRepositoryImpl}.
*
* @return
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INFO/casasndra-named-queries.properties}.
*
* @return
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link Key#CREATE_IF_NOT_FOUND}.
*
* @return
*/
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to
* {@link CassandraRepositoryFactoryBean}.
*
* @return
*/
Class<?> repositoryFactoryBeanClass() default CassandraRepositoryFactoryBean.class;
/**
* Configures the name of the {@link CassandraDataTemplate} bean to be used with the repositories detected.
*
* @return
*/
String cassandraDataTemplateRef() default "cassandraDataTemplate";
/**
* Whether to automatically create indexes for query methods defined in the repository interface.
*
* @return
*/
boolean createIndexesForQueryMethods() default false;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2011 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.repository.query;
import java.io.Serializable;
import org.springframework.data.repository.core.EntityInformation;
/**
* Cassandra specific {@link EntityInformation}.
*
* @author Alex Shvid
*
*/
public interface CassandraEntityInformation<T, ID extends Serializable> extends EntityInformation<T, ID> {
/**
* Returns the name of the table the entity shall be persisted to.
*
* @return
*/
String getTableName();
/**
* Returns the column that the id will be persisted to.
*
* @return
*/
String getIdColumn();
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2011 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.repository.query;
import org.springframework.data.repository.core.EntityMetadata;
/**
* Extension of {@link EntityMetadata} to additionally expose the table name an entity shall be persisted to.
*
* @author Alex Shvid
*
* @param <T>
*/
public interface CassandraEntityMetadata<T> extends EntityMetadata<T> {
/**
* Returns the name of the table the entity shall be persisted to.
*
* @return
*/
String getTableName();
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2010-2012 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.repository.support;
import java.io.Serializable;
import org.springframework.data.cassandra.core.CassandraDataTemplate;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.util.Assert;
/**
* Factory to create {@link CassandraRepository} instances.
*
* @author Alex Shvid
*
*/
public class CassandraRepositoryFactory extends RepositoryFactorySupport {
private final CassandraDataTemplate cassandraDataTemplate;
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
/**
* Creates a new {@link MongoRepositoryFactory} with the given {@link MongoOperations}.
*
* @param mongoOperations must not be {@literal null}
*/
public CassandraRepositoryFactory(CassandraDataTemplate cassandraDataTemplate) {
Assert.notNull(cassandraDataTemplate);
this.cassandraDataTemplate = cassandraDataTemplate;
this.mappingContext = cassandraDataTemplate.getConverter().getMappingContext();
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleCassandraRepository.class;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object getTargetRepository(RepositoryMetadata metadata) {
CassandraEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
return new SimpleCassandraRepository(entityInformation, cassandraDataTemplate);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
*/
@Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> CassandraEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(domainClass);
if (entity == null) {
throw new MappingException(String.format("Could not lookup mapping metadata for domain class %s!",
domainClass.getName()));
}
return new MappingCassandraEntityInformation<T, ID>((CassandraPersistentEntity<T>) entity);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2011 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.repository.support;
import java.io.Serializable;
import org.springframework.data.cassandra.core.CassandraDataTemplate;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.util.Assert;
/**
* {@link org.springframework.beans.factory.FactoryBean} to create {@link CassandraRepository} instances.
*
* @author Alex Shvid
*
*/
public class CassandraRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
RepositoryFactoryBeanSupport<T, S, ID> {
private CassandraDataTemplate cassandraDataTemplate;
@Override
protected RepositoryFactorySupport createRepositoryFactory() {
return new CassandraRepositoryFactory(cassandraDataTemplate);
}
/**
* Configures the {@link CassandraDataTemplate} to be used.
*
* @param operations the operations to set
*/
public void setCassandraDataTemplate(CassandraDataTemplate cassandraDataTemplate) {
this.cassandraDataTemplate = cassandraDataTemplate;
setMappingContext(cassandraDataTemplate.getConverter().getMappingContext());
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.support.RepositoryFactoryBeanSupport
* #afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Assert.notNull(cassandraDataTemplate, "cassandraDataTemplate must not be null!");
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.repository.support;
import java.io.Serializable;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
/**
* {@link CassandraEntityInformation} implementation using a {@link CassandraPersistentEntity} instance to lookup the
* necessary information. Can be configured with a custom collection to be returned which will trump the one returned by
* the {@link CassandraPersistentEntity} if given.
*
* @author Alex Shvid
*
*/
public class MappingCassandraEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
implements CassandraEntityInformation<T, ID> {
private final CassandraPersistentEntity<T> entityMetadata;
private final String customTableName;
/**
* Creates a new {@link MappingCassandraEntityInformation} for the given {@link CassandraPersistentEntity}.
*
* @param entity must not be {@literal null}.
*/
public MappingCassandraEntityInformation(CassandraPersistentEntity<T> entity) {
this(entity, null);
}
/**
* Creates a new {@link MappingCassandraEntityInformation} for the given {@link CassandraPersistentEntity} and custom
* table name.
*
* @param entity must not be {@literal null}.
* @param customTableName
*/
public MappingCassandraEntityInformation(CassandraPersistentEntity<T> entity, String customTableName) {
super(entity.getType());
this.entityMetadata = entity;
this.customTableName = customTableName;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.EntityInformation#getId(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public ID getId(T entity) {
CassandraPersistentProperty idProperty = entityMetadata.getIdProperty();
if (idProperty == null) {
return null;
}
try {
return (ID) BeanWrapper.create(entity, null).getProperty(idProperty);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/* (non-Javadoc)
* @see org.springframework.data.repository.support.EntityInformation#getIdType()
*/
@SuppressWarnings("unchecked")
@Override
public Class<ID> getIdType() {
return (Class<ID>) entityMetadata.getIdProperty().getType();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.CassandraEntityInformation#getTableName()
*/
@Override
public String getTableName() {
return customTableName == null ? entityMetadata.getTable() : customTableName;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.CassandraEntityInformation#getIdColumn()
*/
public String getIdColumn() {
return entityMetadata.getIdProperty().getName();
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright 2010-2012 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.repository.support;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraDataOperations;
import org.springframework.data.cassandra.core.CassandraDataTemplate;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
import org.springframework.util.Assert;
import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
/**
* Repository base implementation for Cassandra.
*
* @author Alex Shvid
*
*/
public class SimpleCassandraRepository<T, ID extends Serializable> implements CassandraRepository<T, ID> {
private final CassandraDataTemplate cassandraDataTemplate;
private final CassandraEntityInformation<T, ID> entityInformation;
/**
* Creates a new {@link SimpleCassandraRepository} for the given {@link CassandraEntityInformation} and
* {@link CassandraDataTemplate}.
*
* @param metadata must not be {@literal null}.
* @param template must not be {@literal null}.
*/
public SimpleCassandraRepository(CassandraEntityInformation<T, ID> metadata,
CassandraDataTemplate cassandraDataTemplate) {
Assert.notNull(cassandraDataTemplate);
Assert.notNull(metadata);
this.entityInformation = metadata;
this.cassandraDataTemplate = cassandraDataTemplate;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
*/
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null!");
cassandraDataTemplate.insert(entity, entityInformation.getTableName());
return entity;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
*/
public <S extends T> List<S> save(Iterable<S> entities) {
Assert.notNull(entities, "The given Iterable of entities not be null!");
List<S> result = new ArrayList<S>();
for (S entity : entities) {
save(entity);
result.add(entity);
}
return result;
}
private Clause getIdClause(ID id) {
Clause clause = QueryBuilder.eq(entityInformation.getIdColumn(), id);
return clause;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
*/
public T findOne(ID id) {
Assert.notNull(id, "The given id must not be null!");
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
select.where(getIdClause(id));
return cassandraDataTemplate.selectOne(select, entityInformation.getJavaType());
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable)
*/
public boolean exists(ID id) {
Assert.notNull(id, "The given id must not be null!");
Select select = QueryBuilder.select().countAll().from(entityInformation.getTableName());
select.where(getIdClause(id));
Long num = cassandraDataTemplate.count(select);
return num != null && num.longValue() > 0;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#count()
*/
public long count() {
return cassandraDataTemplate.count(entityInformation.getTableName());
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
*/
public void delete(ID id) {
Assert.notNull(id, "The given id must not be null!");
Delete delete = QueryBuilder.delete().all().from(entityInformation.getTableName());
delete.where(getIdClause(id));
cassandraDataTemplate.execute(delete.getQueryString());
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
*/
public void delete(T entity) {
Assert.notNull(entity, "The given entity must not be null!");
delete(entityInformation.getId(entity));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
*/
public void delete(Iterable<? extends T> entities) {
Assert.notNull(entities, "The given Iterable of entities not be null!");
for (T entity : entities) {
delete(entity);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#deleteAll()
*/
public void deleteAll() {
cassandraDataTemplate.truncate(entityInformation.getTableName());
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
public List<T> findAll() {
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
return findAll(select);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
*/
public Iterable<T> findAll(Iterable<ID> ids) {
List<ID> parameters = new ArrayList<ID>();
for (ID id : ids) {
parameters.add(id);
}
Clause clause = QueryBuilder.in(entityInformation.getIdColumn(), parameters.toArray());
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
select.where(clause);
return findAll(select);
}
private List<T> findAll(Select query) {
if (query == null) {
return Collections.emptyList();
}
return cassandraDataTemplate.select(query, entityInformation.getJavaType());
}
/**
* Returns the underlying {@link CassandraOperations} instance.
*
* @return
*/
protected CassandraOperations getCassandraOperations() {
return this.cassandraDataTemplate;
}
/**
* Returns the underlying {@link CassandraDataOperations} instance.
*
* @return
*/
protected CassandraDataOperations getCassandraDataOperations() {
return this.cassandraDataTemplate;
}
/**
* @return the entityInformation
*/
protected CassandraEntityInformation<T, ID> getEntityInformation() {
return entityInformation;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2011 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.integration.repository;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.test.integration.table.User;
/**
* Sample repository managing {@link User} entities.
*
* @author Alex Shvid
*
*/
public interface UserRepository extends CassandraRepository<User, String> {
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2011-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.integration.repository;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.core.CassandraDataOperations;
import org.springframework.data.cassandra.test.integration.table.User;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.google.common.collect.Lists;
/**
* Base class for tests for {@link UserRepository}.
*
* @author Alex Shvid
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class UserRepositoryIntegrationTests {
@Autowired
protected UserRepository repository;
@Autowired
protected CassandraDataOperations dataOperations;
User tom, bob, alice, scott;
List<User> all;
@BeforeClass
public static void startCassandra() throws IOException, TTransportException, ConfigurationException,
InterruptedException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml");
}
@Before
public void setUp() throws InterruptedException {
repository.deleteAll();
tom = new User();
tom.setUsername("tom");
tom.setFirstName("Tom");
tom.setLastName("Ron");
tom.setPassword("123");
tom.setPlace("SF");
bob = new User();
bob.setUsername("bob");
bob.setFirstName("Bob");
bob.setLastName("White");
bob.setPassword("555");
bob.setPlace("NY");
alice = new User();
alice.setUsername("alice");
alice.setFirstName("Alice");
alice.setLastName("Red");
alice.setPassword("777");
alice.setPlace("LA");
scott = new User();
scott.setUsername("scott");
scott.setFirstName("Scott");
scott.setLastName("Van");
scott.setPassword("444");
scott.setPlace("Boston");
all = dataOperations.insert(Arrays.asList(tom, bob, alice, scott));
}
@Test
public void findsUserById() throws Exception {
User user = repository.findOne(bob.getUsername());
Assert.assertNotNull(user);
assertEquals(bob, user);
}
@Test
public void findsAll() throws Exception {
List<User> result = Lists.newArrayList(repository.findAll());
assertThat(result.size(), is(all.size()));
assertThat(result.containsAll(all), is(true));
}
@Test
public void findsAllWithGivenIds() {
Iterable<User> result = repository.findAll(Arrays.asList(bob.getUsername(), tom.getUsername()));
assertThat(result, hasItems(bob, tom));
assertThat(result, not(hasItems(alice, scott)));
}
@Test
public void deletesUserCorrectly() throws Exception {
repository.delete(tom);
List<User> result = Lists.newArrayList(repository.findAll());
assertThat(result.size(), is(all.size() - 1));
assertThat(result, not(hasItem(tom)));
}
@Test
public void deletesUserByIdCorrectly() {
repository.delete(tom.getUsername().toString());
List<User> result = Lists.newArrayList(repository.findAll());
assertThat(result.size(), is(all.size() - 1));
assertThat(result, not(hasItem(tom)));
}
@AfterClass
public static void stopCassandra() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
EmbeddedCassandraServerHelper.stopEmbeddedCassandra();
}
private static void assertEquals(User user1, User user2) {
Assert.assertEquals(user1.getUsername(), user2.getUsername());
Assert.assertEquals(user1.getFirstName(), user2.getFirstName());
Assert.assertEquals(user1.getLastName(), user2.getLastName());
Assert.assertEquals(user1.getPlace(), user2.getPlace());
Assert.assertEquals(user1.getPassword(), user2.getPassword());
}
}

View File

@@ -22,7 +22,7 @@ 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
* This is an example of the Users status 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
@@ -63,9 +63,9 @@ public class User {
private String password;
/*
* Age
* Birth Year
*/
private int age;
private int birthYear;
/*
* Following other users in userline
@@ -142,17 +142,42 @@ public class User {
}
/**
* @return Returns the age.
* @return Returns the birthYear.
*/
public int getAge() {
return age;
public int getBirthYear() {
return birthYear;
}
/**
* @param age The age to set.
* @param birthYear The birthYear to set.
*/
public void setAge(int age) {
this.age = age;
public void setBirthYear(int birthYear) {
this.birthYear = birthYear;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

View File

@@ -0,0 +1 @@
User.findByNamedQuery=SELECT firstName FROM table WHERE firstName=?0

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/data/cassandra http://www.springframework.org/schema/data/cassandra/spring-cassandra-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<context:property-placeholder
location="classpath:/org/springframework/data/cassandra/test/integration/repository/cassandra.properties" />
<cassandra:cluster id="cassandra-cluster"
contactPoints="${cassandra.contactPoints}" port="${cassandra.port}"
compression="SNAPPY">
<cassandra:local-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="2" max-connections="8" />
<cassandra:remote-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="1" max-connections="2" />
<cassandra:socket-options
connect-timeout-mls="5000" keep-alive="true" reuse-address="true"
so-linger="60" tcp-no-delay="true" receive-buffer-size="65536"
send-buffer-size="65536" />
</cassandra:cluster>
<bean id="cassandra-mapping"
class=" org.springframework.data.cassandra.mapping.CassandraMappingContext" />
<bean id="cassandra-converter"
class=" org.springframework.data.cassandra.convert.MappingCassandraConverter">
<constructor-arg ref="cassandra-mapping" />
</bean>
<cassandra:keyspace id="cassandra-keyspace" name="${cassandra.keyspace}"
cassandra-cluster-ref="cassandra-cluster" cassandra-converter-ref="cassandra-converter">
<cassandra:keyspace-attributes auto="update"
replication-stategy="SimpleStrategy" replication-factor="1"
durable-writes="true">
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Comment" />
<cassandra:table
entity="org.springframework.data.cassandra.test.integration.table.Notification" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Post" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Timeline" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.User" />
</cassandra:keyspace-attributes>
</cassandra:keyspace>
<cassandra:session id="cassandra-session" cassandra-keyspace-ref="cassandra-keyspace"/>
<bean id="cassandraTemplate" class="org.springframework.cassandra.core.CassandraTemplate">
<constructor-arg ref="cassandra-session" />
</bean>
<bean id="cassandraDataTemplate" class="org.springframework.data.cassandra.core.CassandraDataTemplate">
<constructor-arg ref="cassandra-session" />
<constructor-arg ref="cassandra-converter" />
<constructor-arg value="${cassandra.keyspace}" />
</bean>
<bean class="org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean">
<property name="cassandraDataTemplate" ref="cassandraDataTemplate"/>
<property name="repositoryInterface" value="org.springframework.data.cassandra.test.integration.repository.UserRepository"/>
<property name="namedQueries">
<bean class="org.springframework.data.repository.core.support.PropertiesBasedNamedQueries">
<constructor-arg>
<util:properties location="classpath:/META-INF/cassandra-named-queries.properties" />
</constructor-arg>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,7 @@
cassandra.contactPoints=localhost
cassandra.port=9042
cassandra.keyspace=TestKS123