From 2dd83238af58d877c91f3775879d3ea7290b1d50 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 27 Nov 2019 13:55:14 +0100 Subject: [PATCH] DATACASS-705 - Introduce FactoryBean for SessionFactory. We now provide SessionFactoryFactoryBean as factory bean and initializer for a SessionFactory. Original pull request: #167. --- .../config/AbstractClusterConfiguration.java | 4 + .../CassandraCqlTemplateFactoryBean.java | 26 ++- .../config/CassandraCqlTemplateParser.java | 8 +- .../config/CassandraNamespaceHandler.java | 1 + .../config/CassandraTemplateParser.java | 4 +- .../config/CqlSessionFactoryBean.java | 25 ++ .../cassandra/config/DefaultCqlBeanNames.java | 2 + .../SessionFactoryBeanDefinitionParser.java | 68 ++++++ .../config/SessionFactoryFactoryBean.java | 216 ++++++++++++++++++ .../core/mapping/SimpleUserTypeResolver.java | 2 +- .../CassandraNamespaceIntegrationTests.java | 29 ++- ...andraNamespaceIntegrationTests-context.xml | 8 +- .../data/cassandra/config/schema.cql | 1 + src/main/asciidoc/reference/cassandra.adoc | 2 - 14 files changed, 373 insertions(+), 23 deletions(-) create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryBeanDefinitionParser.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryFactoryBean.java create mode 100644 spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/schema.cql diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java index fa2510265..f8d1517a8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java @@ -330,7 +330,9 @@ public abstract class AbstractClusterConfiguration { * {@link com.datastax.driver.core.Cluster} initialization. * * @return the list of startup scripts, may be empty but never {@link null} + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer}. */ + @Deprecated protected List getStartupScripts() { return Collections.emptyList(); } @@ -340,7 +342,9 @@ public abstract class AbstractClusterConfiguration { * {@link com.datastax.driver.core.Cluster} shutdown. * * @return the list of shutdown scripts, may be empty but never {@link null} + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer}. */ + @Deprecated protected List getShutdownScripts() { return Collections.emptyList(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java index d50ee7bb0..85dc097b4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java @@ -17,7 +17,9 @@ package org.springframework.data.cassandra.config; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.cassandra.SessionFactory; import org.springframework.data.cassandra.core.cql.CqlTemplate; +import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -33,7 +35,7 @@ public class CassandraCqlTemplateFactoryBean implements FactoryBean private @Nullable CqlTemplate template; - private @Nullable Session session; + private @Nullable SessionFactory sessionFactory; /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() @@ -65,9 +67,9 @@ public class CassandraCqlTemplateFactoryBean implements FactoryBean @Override public void afterPropertiesSet() throws Exception { - Assert.notNull(session, "Session must not be null"); + Assert.notNull(sessionFactory, "SessionFactory must not be null"); - this.template = new CqlTemplate(session); + this.template = new CqlTemplate(sessionFactory); } /** @@ -81,6 +83,22 @@ public class CassandraCqlTemplateFactoryBean implements FactoryBean Assert.notNull(session, "Session must not be null"); - this.session = session; + setSessionFactory(new DefaultSessionFactory(session)); + } + + /** + * Sets the Cassandra {@link SessionFactory} to use. The {@link CqlTemplate} will use the logged keyspace of the + * underlying {@link SessionFactory}. Don't change the keyspace using CQL but use an appropriate + * {@link SessionFactory}. + * + * @param sessionFactory must not be {@literal null}. + * @see SessionFactory + * @see org.springframework.data.cassandra.core.cql.session.lookup.AbstractRoutingSessionFactory + */ + public void setSessionFactory(SessionFactory sessionFactory) { + + Assert.notNull(sessionFactory, "SessionFactory must not be null"); + + this.sessionFactory = sessionFactory; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateParser.java index 1c4404f9b..f5e555f14 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateParser.java @@ -57,6 +57,12 @@ class CassandraCqlTemplateParser extends AbstractSingleBeanDefinitionParser { */ @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - addOptionalPropertyReference(builder, "session", element, "session-ref", DefaultCqlBeanNames.SESSION); + + if (element.hasAttribute("session-factory-ref")) { + addOptionalPropertyReference(builder, "sessionFactory", element, "session-factory-ref", + DefaultCqlBeanNames.SESSION); + } else { + addOptionalPropertyReference(builder, "session", element, "session-ref", DefaultCqlBeanNames.SESSION); + } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraNamespaceHandler.java index e695bc29c..0723ba4b9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraNamespaceHandler.java @@ -35,6 +35,7 @@ public class CassandraNamespaceHandler extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("session", new CqlSessionParser()); + registerBeanDefinitionParser("session-factory", new SessionFactoryBeanDefinitionParser()); registerBeanDefinitionParser("template", new CassandraTemplateParser()); registerBeanDefinitionParser("cql-template", new CassandraCqlTemplateParser()); registerBeanDefinitionParser("auditing", new CassandraAuditingBeanDefinitionParser()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateParser.java index a521d1197..8dfcb19b3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateParser.java @@ -63,8 +63,10 @@ class CassandraTemplateParser extends AbstractSingleBeanDefinitionParser { super.doParse(element, parserContext, builder); - if (StringUtils.hasText(element.getAttribute("cql-template-ref"))) { + if (element.hasAttribute("cql-template-ref")) { addRequiredPropertyReference(builder, "cqlOperations", element, "cql-template-ref"); + } else if (element.hasAttribute("session-factory-ref")) { + addRequiredPropertyReference(builder, "sessionFactory", element, "session-factory-ref"); } else { addOptionalPropertyReference(builder, "session", element, "session-ref", DefaultBeanNames.SESSION); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CqlSessionFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CqlSessionFactoryBean.java index 0900417b4..ecb45998f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CqlSessionFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CqlSessionFactoryBean.java @@ -282,6 +282,10 @@ public class CqlSessionFactoryBean implements FactoryBean, Initializing /** * Sets CQL scripts to be executed immediately after the session is connected. + * + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} or + * {@link SessionFactoryFactoryBean} with + * {@link org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator} instead. */ public void setStartupScripts(@Nullable List scripts) { this.startupScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList()); @@ -289,21 +293,36 @@ public class CqlSessionFactoryBean implements FactoryBean, Initializing /** * Returns an unmodifiable list of startup scripts. + * + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} or + * {@link SessionFactoryFactoryBean} with + * {@link org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator} instead. */ + @Deprecated public List getStartupScripts() { return Collections.unmodifiableList(this.startupScripts); } /** * Sets CQL scripts to be executed immediately before the session is shutdown. + * + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} or + * {@link SessionFactoryFactoryBean} with + * {@link org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator} instead. */ + @Deprecated public void setShutdownScripts(@Nullable List scripts) { this.shutdownScripts = scripts != null ? new ArrayList<>(scripts) : Collections.emptyList(); } /** * Returns an unmodifiable list of shutdown scripts. + * + * @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} or + * {@link SessionFactoryFactoryBean} with + * {@link org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator} instead. */ + @Deprecated public List getShutdownScripts() { return Collections.unmodifiableList(this.shutdownScripts); } @@ -313,7 +332,10 @@ public class CqlSessionFactoryBean implements FactoryBean, Initializing * {@link CassandraMappingContext} inside {@code converter}. * * @param converter must not be {@literal null}. + * @deprecated Use {@link CassandraSessionFactoryBean} with + * {@link CassandraSessionFactoryBean#setConverter(CassandraConverter)} instead. */ + @Deprecated public void setConverter(CassandraConverter converter) { Assert.notNull(converter, "CassandraConverter must not be null"); @@ -345,7 +367,10 @@ public class CqlSessionFactoryBean implements FactoryBean, Initializing * Set the {@link SchemaAction}. * * @param schemaAction must not be {@literal null}. + * @deprecated Use {@link CassandraSessionFactoryBean} with + * {@link CassandraSessionFactoryBean#setSchemaAction(SchemaAction)} instead. */ + @Deprecated public void setSchemaAction(SchemaAction schemaAction) { Assert.notNull(schemaAction, "SchemaAction must not be null"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultCqlBeanNames.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultCqlBeanNames.java index bb473b345..b97f9cb13 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultCqlBeanNames.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultCqlBeanNames.java @@ -19,10 +19,12 @@ package org.springframework.data.cassandra.config; * @author Alex Shvid * @author David Webb * @author Matthew T. Adams + * @author Mark Paluch */ public interface DefaultCqlBeanNames { String CLUSTER = "cassandraCluster"; String SESSION = "cassandraSession"; + String SESSION_FACTORY = "cassandraSessionFactory"; String TEMPLATE = "cqlTemplate"; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryBeanDefinitionParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryBeanDefinitionParser.java new file mode 100644 index 000000000..99dfce066 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryBeanDefinitionParser.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013-2019 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 + * + * https://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.config; + +import static org.springframework.data.cassandra.config.ParsingUtils.*; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; + +import org.w3c.dom.Element; + +/** + * Parser for <session-factory> definitions. + * + * @author Mark Paluch + */ +class SessionFactoryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + + /* (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element) + */ + @Override + protected Class getBeanClass(Element element) { + return SessionFactoryFactoryBean.class; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext) + */ + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + + String id = super.resolveId(element, definition, parserContext); + + return StringUtils.hasText(id) ? id : DefaultBeanNames.SESSION_FACTORY; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder) + */ + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + addOptionalPropertyReference(builder, "session", element, "session-ref", DefaultBeanNames.SESSION); + addOptionalPropertyReference(builder, "converter", element, "cassandra-converter-ref", DefaultBeanNames.CONVERTER); + addOptionalPropertyValue(builder, "schemaAction", element, "schema-action", SchemaAction.NONE.name()); + + InitializeKeyspaceBeanDefinitionParser.parseKeyspacePopulator(element, builder); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryFactoryBean.java new file mode 100644 index 000000000..27a8e3fa0 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SessionFactoryFactoryBean.java @@ -0,0 +1,216 @@ +/* + * Copyright 2013-2019 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 + * + * https://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.config; + +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.data.cassandra.SessionFactory; +import org.springframework.data.cassandra.core.CassandraAdminOperations; +import org.springframework.data.cassandra.core.CassandraAdminTemplate; +import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaCreator; +import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaDropper; +import org.springframework.data.cassandra.core.convert.CassandraConverter; +import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; +import org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator; +import org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer; +import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +import com.datastax.driver.core.Session; + +/** + * Factory to create and configure a Cassandra {@link SessionFactory} with support for executing CQL and initializing + * the database schema (a.k.a. keyspace). This factory bean invokes a {@link SessionFactoryInitializer} to prepare a + * keyspace before applying {@link SchemaAction schema actions} such as creating user-defined types and tables. + * + * @author Mark Paluch + * @since 3.0 + * @see SessionFactoryInitializer + */ +public class SessionFactoryFactoryBean extends AbstractFactoryBean { + + protected static final boolean DEFAULT_CREATE_IF_NOT_EXISTS = false; + protected static final boolean DEFAULT_DROP_TABLES = false; + protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false; + + private Session session; + + private @Nullable KeyspacePopulator keyspacePopulator; + + private @Nullable KeyspacePopulator keyspaceCleaner; + + private CassandraConverter converter; + + private SchemaAction schemaAction = SchemaAction.NONE; + + /** + * Set the {@link Session} to use. + * + * @param session must not be {@literal null}. + */ + public void setSession(Session session) { + + Assert.notNull(session, "Session must not be null"); + + this.session = session; + } + + /** + * Set the {@link KeyspacePopulator} to execute during the bean initialization phase. + * + * @param keyspacePopulator the {@link KeyspacePopulator} to use during initialization. + * @see #setKeyspaceCleaner + */ + public void setKeyspacePopulator(KeyspacePopulator keyspacePopulator) { + this.keyspacePopulator = keyspacePopulator; + } + + /** + * Set the {@link KeyspacePopulator} to execute during the bean destruction phase, cleaning up the keyspace and + * leaving it in a known state for others. + * + * @param keyspaceCleaner the {@link KeyspacePopulator} to use during destruction. + * @see #setKeyspacePopulator + */ + public void setKeyspaceCleaner(KeyspacePopulator keyspaceCleaner) { + this.keyspaceCleaner = keyspaceCleaner; + } + + /** + * Set the {@link CassandraConverter} to use. Schema actions will derive table and user type information from the + * {@link CassandraMappingContext} inside {@code converter}. + * + * @param converter must not be {@literal null}. + */ + public void setConverter(CassandraConverter converter) { + + Assert.notNull(converter, "CassandraConverter must not be null"); + + this.converter = converter; + } + + /** + * Set the {@link SchemaAction}. + * + * @param schemaAction must not be {@literal null}. + */ + public void setSchemaAction(SchemaAction schemaAction) { + + Assert.notNull(schemaAction, "SchemaAction must not be null"); + + this.schemaAction = schemaAction; + } + + /* + * (non-Javadoc) + * @see org.springframework.cassandra.config.CassandraCqlSessionFactoryBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception { + + Assert.state(this.session != null, "Session was not properly initialized"); + Assert.state(this.converter != null, "Converter was not properly initialized"); + + super.afterPropertiesSet(); + + if (this.keyspacePopulator != null) { + this.keyspacePopulator.populate(getObject().getSession()); + } + + performSchemaAction(); + } + + @Override + public void destroy() throws Exception { + if (this.keyspaceCleaner != null) { + this.keyspaceCleaner.populate(getObject().getSession()); + } + } + + @Nullable + @Override + public Class getObjectType() { + return SessionFactory.class; + } + + @Override + protected SessionFactory createInstance() { + return new DefaultSessionFactory(session); + } + + /** + * Perform the configure {@link SchemaAction} using {@link CassandraMappingContext} metadata. + */ + protected void performSchemaAction() throws Exception { + + boolean create = false; + boolean drop = DEFAULT_DROP_TABLES; + boolean dropUnused = DEFAULT_DROP_UNUSED_TABLES; + boolean ifNotExists = DEFAULT_CREATE_IF_NOT_EXISTS; + + switch (this.schemaAction) { + case RECREATE_DROP_UNUSED: + dropUnused = true; + case RECREATE: + drop = true; + case CREATE_IF_NOT_EXISTS: + ifNotExists = SchemaAction.CREATE_IF_NOT_EXISTS.equals(this.schemaAction); + case CREATE: + create = true; + case NONE: + default: + // do nothing + } + + if (create) { + createTables(drop, dropUnused, ifNotExists); + } + } + + /** + * Perform schema actions. + * + * @param drop {@literal true} to drop types/tables. + * @param dropUnused {@literal true} to drop unused types/tables (i.e. types/tables not know to be used by + * {@link CassandraMappingContext}). + * @param ifNotExists {@literal true} to perform creations fail-safe by adding {@code IF NOT EXISTS} to each creation + * statement. + */ + protected void createTables(boolean drop, boolean dropUnused, boolean ifNotExists) throws Exception { + performSchemaActions(drop, dropUnused, ifNotExists); + } + + private void performSchemaActions(boolean drop, boolean dropUnused, boolean ifNotExists) throws Exception { + + CassandraAdminOperations adminOperations = new CassandraAdminTemplate(getObject(), this.converter); + + CassandraPersistentEntitySchemaCreator schemaCreator = new CassandraPersistentEntitySchemaCreator( + this.converter.getMappingContext(), adminOperations); + + if (drop) { + + CassandraPersistentEntitySchemaDropper schemaDropper = new CassandraPersistentEntitySchemaDropper( + this.converter.getMappingContext(), adminOperations); + + schemaDropper.dropTables(dropUnused); + schemaDropper.dropUserTypes(dropUnused); + } + + schemaCreator.createUserTypes(ifNotExists); + schemaCreator.createTables(ifNotExists); + schemaCreator.createIndexes(ifNotExists); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java index 67d275f06..5d034a058 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java @@ -45,7 +45,7 @@ public class SimpleUserTypeResolver implements UserTypeResolver { */ public SimpleUserTypeResolver(Session session) { - Assert.notNull(session, "Serssion must not be null"); + Assert.notNull(session, "Session must not be null"); this.keyspaceName = session.getLoggedKeyspace(); this.cluster = session.getCluster(); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests.java index 0609a8d48..cba0d9154 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests.java @@ -15,7 +15,10 @@ */ package org.springframework.data.cassandra.config; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,13 +34,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.util.ReflectionTestUtils; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Configuration; -import com.datastax.driver.core.HostDistance; -import com.datastax.driver.core.PoolingOptions; -import com.datastax.driver.core.ProtocolOptions.Compression; -import com.datastax.driver.core.SocketOptions; - /** * Integration tests for XML-based Cassandra configuration using the Cassandra namespace parsed with * {@link CqlNamespaceHandler}. @@ -49,16 +45,25 @@ import com.datastax.driver.core.SocketOptions; @SuppressWarnings("unused") public class CassandraNamespaceIntegrationTests extends AbstractSpringDataEmbeddedCassandraIntegrationTest { - @Autowired - private ApplicationContext applicationContext; + @Autowired private ApplicationContext applicationContext; + + @Test // DATACASS-705 + public void keyspaceShouldBeInitialized() { + + CqlTemplate cqlTemplate = this.applicationContext.getBean(CqlTemplate.class); + + List> result = cqlTemplate.queryForList("SELECT * FROM mytable1"); + + assertThat(result).isEmpty(); + } @Test // DATACASS-172 public void mappingContextShouldHaveUserTypeResolverConfigured() { CassandraMappingContext mappingContext = this.applicationContext.getBean(CassandraMappingContext.class); - SimpleUserTypeResolver userTypeResolver = - (SimpleUserTypeResolver) ReflectionTestUtils.getField(mappingContext, "userTypeResolver"); + SimpleUserTypeResolver userTypeResolver = (SimpleUserTypeResolver) ReflectionTestUtils.getField(mappingContext, + "userTypeResolver"); assertThat(userTypeResolver).isNotNull(); } diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests-context.xml index 7812afc27..2c2c3f320 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/CassandraNamespaceIntegrationTests-context.xml @@ -17,12 +17,16 @@ + keyspace-name="${cassandra.keyspace}"> + + + + diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/schema.cql b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/schema.cql new file mode 100644 index 000000000..7d740a0f4 --- /dev/null +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/config/schema.cql @@ -0,0 +1 @@ +create table if not exists mytable1 (id uuid primary key, column1 text); diff --git a/src/main/asciidoc/reference/cassandra.adoc b/src/main/asciidoc/reference/cassandra.adoc index eabdb9d6d..bd11ddbce 100644 --- a/src/main/asciidoc/reference/cassandra.adoc +++ b/src/main/asciidoc/reference/cassandra.adoc @@ -610,8 +610,6 @@ NOTE: Keyspace creation allows rapid bootstrapping without the need of external for certain scenarios but should be used with care. Dropping a keyspace on application shutdown removes the keyspace and all data from the tables in the keyspace. - - [[cassandra.schema-management.initializing]] === Initializing a `SessionFactory`