diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java index a784bcd1d..aae08bdce 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cassandra.config; import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -32,6 +32,7 @@ import org.springframework.cassandra.core.cql.generator.DropKeyspaceCqlGenerator import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification; import org.springframework.cassandra.core.keyspace.KeyspaceActionSpecification; +import org.springframework.cassandra.core.util.CollectionUtils; import org.springframework.cassandra.support.CassandraExceptionTranslator; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; @@ -60,6 +61,7 @@ import com.datastax.driver.core.policies.RetryPolicy; * @author David Webb * @author Kirk Clemens * @author Jorge Davison + * @author John Blum * @see org.springframework.beans.factory.InitializingBean * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.beans.factory.FactoryBean @@ -264,36 +266,32 @@ public class CassandraCqlClusterFactoryBean protected void executeSpecsAndScripts(@SuppressWarnings("rawtypes") List specs, List scripts) { Session system = null; - CqlTemplate template = null; try { - if (specs != null) { - system = specs.size() == 0 ? null : cluster.connect(); - template = system == null ? null : new CqlTemplate(system); + if (!CollectionUtils.isEmpty(specs)) { + system = cluster.connect(); - Iterator i = specs.iterator(); - while (i.hasNext()) { - KeyspaceActionSpecification spec = (KeyspaceActionSpecification) i.next(); + CqlTemplate template = new CqlTemplate(system); + + for (Object spec : specs) { String cql = (spec instanceof CreateKeyspaceSpecification) - ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) spec).toCql() - : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); + ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) spec).toCql() + : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); + + if (log.isDebugEnabled()) { + log.debug("executing raw CQL [{}]", cql); + } template.execute(cql); } } - if (scripts != null) { + if (!CollectionUtils.isEmpty(scripts)) { + system = (system != null ? system : cluster.connect()); - if (system == null) { - system = scripts.size() == 0 ? null : cluster.connect(); - } - - if (template == null) { - template = system == null ? null : new CqlTemplate(system); - } + CqlTemplate template = new CqlTemplate(system); for (String script : scripts) { - if (log.isDebugEnabled()) { log.debug("executing raw CQL [{}]", script); } @@ -302,7 +300,6 @@ public class CassandraCqlClusterFactoryBean } } } finally { - if (system != null) { system.close(); } @@ -312,8 +309,6 @@ public class CassandraCqlClusterFactoryBean /** * Set a comma-delimited string of the contact points (hosts) to connect to. Default is {@code localhost}, see * {@link #DEFAULT_CONTACT_POINTS}. - * - * @param contactPoints */ public void setContactPoints(String contactPoints) { this.contactPoints = contactPoints; @@ -321,8 +316,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the port for the contact points. Default is {@code 9042}, see {@link #DEFAULT_PORT}. - * - * @param port */ public void setPort(int port) { this.port = port; @@ -330,8 +323,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link CompressionType}. Default is uncompressed. - * - * @param compressionType */ public void setCompressionType(CompressionType compressionType) { this.compressionType = compressionType; @@ -339,8 +330,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link PoolingOptions}. - * - * @param poolingOptions */ public void setPoolingOptions(PoolingOptions poolingOptions) { this.poolingOptions = poolingOptions; @@ -349,7 +338,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link ProtocolVersion}. * - * @param protocolVersion * @since 1.4 */ public void setProtocolVersion(ProtocolVersion protocolVersion) { @@ -358,8 +346,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link SocketOptions} containing low-level socket options. - * - * @param socketOptions */ public void setSocketOptions(SocketOptions socketOptions) { this.socketOptions = socketOptions; @@ -367,8 +353,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link QueryOptions}. - * - * @param queryOptions */ public void setQueryOptions(QueryOptions queryOptions) { this.queryOptions = queryOptions; @@ -376,8 +360,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link AuthProvider}. Default is unauthenticated. - * - * @param authProvider */ public void setAuthProvider(AuthProvider authProvider) { this.authProvider = authProvider; @@ -385,8 +367,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link LoadBalancingPolicy}. - * - * @param loadBalancingPolicy */ public void setLoadBalancingPolicy(LoadBalancingPolicy loadBalancingPolicy) { this.loadBalancingPolicy = loadBalancingPolicy; @@ -394,8 +374,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link ReconnectionPolicy}. - * - * @param reconnectionPolicy */ public void setReconnectionPolicy(ReconnectionPolicy reconnectionPolicy) { this.reconnectionPolicy = reconnectionPolicy; @@ -403,8 +381,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link RetryPolicy}. - * - * @param retryPolicy */ public void setRetryPolicy(RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; @@ -412,8 +388,6 @@ public class CassandraCqlClusterFactoryBean /** * Set whether metrics are enabled. Default is {@literal true}, see {@link #DEFAULT_METRICS_ENABLED}. - * - * @param metricsEnabled */ public void setMetricsEnabled(boolean metricsEnabled) { this.metricsEnabled = metricsEnabled; @@ -424,8 +398,6 @@ public class CassandraCqlClusterFactoryBean * this factory is {@link #afterPropertiesSet() initialized}. {@link CreateKeyspaceSpecification Create keyspace * specifications} are executed on a system session with no keyspace set, before executing * {@link #setStartupScripts(List)}. - * - * @param specifications */ public void setKeyspaceCreations(List specifications) { this.keyspaceCreations = specifications; @@ -433,8 +405,6 @@ public class CassandraCqlClusterFactoryBean /** * Return a {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}. - * - * @return */ public List getKeyspaceCreations() { return keyspaceCreations; @@ -444,8 +414,6 @@ public class CassandraCqlClusterFactoryBean * Set a {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications} that are executed when this * factory is {@link #destroy() destroyed}. {@link DropKeyspaceSpecification Drop keyspace specifications} are * executed on a system session with no keyspace set, before executing {@link #setShutdownScripts(List)}. - * - * @param specifications */ public void setKeyspaceDrops(List specifications) { this.keyspaceDrops = specifications; @@ -453,8 +421,6 @@ public class CassandraCqlClusterFactoryBean /** * Reurn the {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications}. - * - * @return */ public List getKeyspaceDrops() { return keyspaceDrops; @@ -464,8 +430,6 @@ public class CassandraCqlClusterFactoryBean * Set a {@link List} of raw {@link String CQL statements} that are executed when this factory is * {@link #afterPropertiesSet() initialized}. Scripts are executed on a system session with no keyspace set, after * executing {@link #setKeyspaceCreations(List)}. - * - * @param scripts */ public void setStartupScripts(List scripts) { this.startupScripts = scripts; @@ -479,8 +443,6 @@ public class CassandraCqlClusterFactoryBean * Set a {@link List} of raw {@link String CQL statements} that are executed when this factory is {@link #destroy() * destroyed}. {@link DropKeyspaceSpecification Drop keyspace specifications} are executed on a system session with no * keyspace set, after executing {@link #setKeyspaceDrops(List)}. - * - * @param scripts */ public void setShutdownScripts(List scripts) { this.shutdownScripts = scripts; @@ -568,6 +530,7 @@ public class CassandraCqlClusterFactoryBean case SNAPPY: return Compression.SNAPPY; } + throw new IllegalArgumentException("unknown compression type " + type); } } diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBean.java b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBean.java index b41f0c135..1e4f5bcf1 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBean.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBean.java @@ -40,7 +40,7 @@ import com.datastax.driver.core.Session; /** * Factory for creating and configuring a Cassandra {@link Session}, which is a thread-safe singleton. * As such, it is sufficient to have one {@link Session} per application and keyspace. - * + * * @author Alex Shvid * @author Matthew T. Adams * @author John Blum diff --git a/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBeanUnitTests.java b/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBeanUnitTests.java index b1b66b360..1c0ec18d6 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBeanUnitTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlSessionFactoryBeanUnitTests.java @@ -16,24 +16,11 @@ package org.springframework.cassandra.config; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.sameInstance; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Arrays; @@ -58,14 +45,8 @@ import com.datastax.driver.core.Session; * and functionality of the {@link CassandraCqlSessionFactoryBean} class. * * @author John Blum - * @see org.junit.Rule - * @see org.junit.Test - * @see org.junit.rules.ExpectedException - * @see org.junit.runner.RunWith - * @see org.mockito.Mock - * @see org.mockito.Mockito - * @see org.mockito.runners.MockitoJUnitRunner * @see org.springframework.cassandra.config.CassandraCqlSessionFactoryBean + * @see , CassandraPersistentProperty> implements - CassandraMappingContext, ApplicationContextAware { +public class BasicCassandraMappingContext extends AbstractMappingContext, CassandraPersistentProperty> + implements CassandraMappingContext, ApplicationContextAware { protected ApplicationContext context; - protected Mapping mapping = new Mapping(); + protected ClassLoader beanClassLoader; + protected CassandraPersistentEntityMetadataVerifier verifier = new BasicCassandraPersistentEntityMetadataVerifier(); + protected Mapping mapping = new Mapping(); + // useful caches + protected Map, CassandraPersistentEntity> entitiesByType = new HashMap, CassandraPersistentEntity>(); protected Map>> entitySetsByTableName = new HashMap>>(); + protected Set> nonPrimaryKeyEntities = new HashSet>(); protected Set> primaryKeyEntities = new HashSet>(); - protected Map, CassandraPersistentEntity> entitiesByType = new HashMap, CassandraPersistentEntity>(); /** * Creates a new {@link BasicCassandraMappingContext}. @@ -75,9 +79,7 @@ public class BasicCassandraMappingContext extends @Override public void initialize() { - super.initialize(); - processMappingOverrides(); } @@ -129,9 +131,11 @@ public class BasicCassandraMappingContext extends // now do some caching of the entity Set> entities = entitySetsByTableName.get(entity.getTableName()); + if (entities == null) { entities = new HashSet>(); } + entities.add(entity); entitySetsByTableName.put(entity.getTableName(), entities); @@ -180,13 +184,13 @@ public class BasicCassandraMappingContext extends if (pkProp.isPartitionKeyColumn()) { spec.partitionKeyColumn(pkProp.getColumnName(), pkProp.getDataType()); } else { // it's a cluster column - spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), pkProp.getPrimaryKeyOrdering()); + spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), + pkProp.getPrimaryKeyOrdering()); } } }); } else { - if (prop.isIdProperty() || prop.isPartitionKeyColumn()) { spec.partitionKeyColumn(prop.getColumnName(), prop.getDataType()); } else if (prop.isClusterKeyColumn()) { @@ -226,20 +230,25 @@ public class BasicCassandraMappingContext extends } String entityClassName = entityMapping.getEntityClassName(); + Class entityClass; + try { entityClass = ClassUtils.forName(entityClassName, beanClassLoader); } catch (ClassNotFoundException e) { - throw new IllegalStateException(String.format("unknown persistent entity name [%s]", entityClassName), e); + throw new IllegalStateException(String.format("unknown persistent entity name [%s]", + entityClassName), e); } CassandraPersistentEntity entity = getPersistentEntity(entityClass); if (entity == null) { - throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", entityClassName)); + throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", + entityClassName)); } String tableName = entityMapping.getTableName(); + if (StringUtils.hasText(tableName)) { entity.setTableName(cqlId(tableName, Boolean.valueOf(entityMapping.getForceQuote()))); } @@ -258,13 +267,16 @@ public class BasicCassandraMappingContext extends protected void processMappingOverride(CassandraPersistentEntity entity, PropertyMapping mapping) { CassandraPersistentProperty property = entity.getPersistentProperty(mapping.getPropertyName()); + if (property == null) { throw new IllegalArgumentException(String.format("entity class [%s] has no persistent property named [%s]", - entity.getType().getName(), mapping.getPropertyName())); + entity.getType().getName(), mapping.getPropertyName())); } boolean forceQuote = false; + String value = mapping.getForceQuote(); + if (StringUtils.hasText(value)) { property.setForceQuote(forceQuote = Boolean.valueOf(value)); } @@ -274,7 +286,6 @@ public class BasicCassandraMappingContext extends if (StringUtils.hasText(value)) { property.setColumnName(cqlId(value, forceQuote)); } - } public void setBeanClassLoader(ClassLoader beanClassLoader) { @@ -285,6 +296,7 @@ public class BasicCassandraMappingContext extends public CassandraPersistentEntity getExistingPersistentEntity(Class type) { CassandraPersistentEntity entity = entitiesByType.get(type); + if (entity != null) { return entity; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBeanUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBeanUnitTests.java index 91bab047f..ff47a3b42 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBeanUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBeanUnitTests.java @@ -16,28 +16,14 @@ package org.springframework.data.cassandra.config; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.springframework.data.cassandra.config.CassandraSessionFactoryBean.DEFAULT_CREATE_IF_NOT_EXISTS; -import static org.springframework.data.cassandra.config.CassandraSessionFactoryBean.DEFAULT_DROP_TABLES; -import static org.springframework.data.cassandra.config.CassandraSessionFactoryBean.DEFAULT_DROP_UNUSED_TABLES; +import static org.mockito.Mockito.*; +import static org.springframework.data.cassandra.config.CassandraSessionFactoryBean.*; import java.util.Collections; import java.util.Map; @@ -68,14 +54,8 @@ import com.datastax.driver.core.TableMetadata; * of the {@link CassandraSessionFactoryBean} class. * * @author John Blum - * @see org.junit.Rule - * @see org.junit.Test - * @see org.junit.rules.ExpectedException - * @see org.junit.runner.RunWith - * @see org.mockito.Mock - * @see org.mockito.Mockito - * @see org.mockito.runners.MockitoJUnitRunner * @see org.springframework.data.cassandra.config.CassandraSessionFactoryBean + * @see