DATACASS-721 - Refactor codebase around uses of the new DataStax 4.x Driver API.

This commit is contained in:
John Blum
2020-01-21 21:24:23 -08:00
parent c341025138
commit 6bf448adac
6 changed files with 531 additions and 482 deletions

View File

@@ -15,21 +15,23 @@
*/
package org.springframework.data.cassandra;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.session.Session;
/**
* A factory for Apache Cassandra sessions.
* <p>
* A factory for Apache Cassandra {@link Session sessions}.
*
* A {@link SessionFactory} object is the preferred means of getting a connection. The {@link SessionFactory} interface
* is implemented by a {@link CqlSession} provider.
* <p>
*
* A {@link SessionFactory} object can have properties that can be modified when necessary. For example, if the
* {@link CqlSession} is moved to a different server, the property for the server can be changed. The benefit is that
* because the data source's properties can be changed, any code accessing that {@link SessionFactory} does not need to
* be changed.
*
* @author Mark Paluch
* @see com.datastax.oss.driver.api.core.CqlSession
* @see com.datastax.oss.driver.api.core.session.Session
* @since 2.0
*/
@FunctionalInterface
@@ -40,6 +42,7 @@ public interface SessionFactory {
* object represents.
*
* @return a {@link CqlSession} to Apache Cassandra.
* @see com.datastax.oss.driver.api.core.CqlSession
*/
CqlSession getSession();

View File

@@ -19,10 +19,7 @@ import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
@@ -41,7 +38,6 @@ import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
@@ -55,23 +51,57 @@ import com.datastax.oss.driver.api.core.CqlSession;
* @author Mark Paluch
*/
@Configuration
@SuppressWarnings("unused")
public abstract class AbstractCassandraConfiguration extends AbstractSessionConfiguration
implements BeanClassLoaderAware, BeanFactoryAware {
implements BeanClassLoaderAware {
private @Nullable ClassLoader beanClassLoader;
private @Nullable BeanFactory beanFactory;
/**
* Returns the initialized {@link CqlSession} instance.
* Creates a {@link CassandraConverter} using the configured {@link #cassandraMapping()}. Will apply all specified
* {@link #customConversions()}.
*
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
* @return {@link CassandraConverter} used to convert Java and Cassandra value types during the mapping process.
* @see #cassandraMapping()
* @see #customConversions()
*/
protected SessionFactory getRequiredSessionFactory() {
@Bean
public CassandraConverter cassandraConverter() {
Assert.state(beanFactory != null, "BeanFactory not initialized");
MappingCassandraConverter mappingCassandraConverter =
new MappingCassandraConverter(requireBeanOfType(CassandraMappingContext.class));
return beanFactory.getBean(SessionFactory.class);
mappingCassandraConverter.setCustomConversions(requireBeanOfType(CassandraCustomConversions.class));
return mappingCassandraConverter;
}
/**
* Return the {@link MappingContext} instance to map Entities to properties.
*
* @throws ClassNotFoundException if the Cassandra Entity class type identified by name cannot be found during the
* scan.
* @see CassandraMappingContext
*/
@Bean
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
UserTypeResolver userTypeResolver =
new SimpleUserTypeResolver(getRequiredSession(), CqlIdentifier.fromCql(getKeyspaceName()));
CassandraMappingContext mappingContext =
new CassandraMappingContext(userTypeResolver, SimpleTupleTypeFactory.DEFAULT);
CustomConversions customConversions = requireBeanOfType(CustomConversions.class);
getBeanClassLoader().ifPresent(mappingContext::setBeanClassLoader);
mappingContext.setCodecRegistry(getRequiredSession().getContext().getCodecRegistry());
mappingContext.setCustomConversions(customConversions);
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
return mappingContext;
}
/**
@@ -91,84 +121,23 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
SessionFactoryFactoryBean bean = new SessionFactoryFactoryBean();
// Initialize the CqlSession reference first since it is required, or must not be null.
bean.setSession(cqlSession);
bean.setConverter(beanFactory.getBean(CassandraConverter.class));
bean.setSchemaAction(getSchemaAction());
bean.setKeyspacePopulator(keyspacePopulator());
bean.setConverter(requireBeanOfType(CassandraConverter.class));
bean.setKeyspaceCleaner(keyspaceCleaner());
bean.setKeyspacePopulator(keyspacePopulator());
bean.setSchemaAction(getSchemaAction());
return bean;
}
/**
* Creates a {@link KeyspacePopulator} to initialize the keyspace.
*
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
*/
@Nullable
protected KeyspacePopulator keyspacePopulator() {
return null;
}
/**
* Creates a {@link KeyspacePopulator} to cleanup the keyspace.
*
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
*/
@Nullable
protected KeyspacePopulator keyspaceCleaner() {
return null;
}
/**
* Creates a {@link CassandraConverter} using the configured {@link #cassandraMapping()}. Will apply all specified
* {@link #customConversions()}.
*
* @return {@link CassandraConverter} used to convert Java and Cassandra value types during the mapping process.
* @see #cassandraMapping()
* @see #customConversions()
* Creates a {@link CassandraAdminTemplate}.
*/
@Bean
public CassandraConverter cassandraConverter() {
MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(
beanFactory.getBean(CassandraMappingContext.class));
mappingCassandraConverter.setCustomConversions(beanFactory.getBean(CassandraCustomConversions.class));
return mappingCassandraConverter;
}
/**
* Return the {@link MappingContext} instance to map Entities to properties.
*
* @throws ClassNotFoundException if the Cassandra Entity class type identified by name cannot be found during the
* scan.
* @see CassandraMappingContext
*/
@Bean
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
UserTypeResolver userTypeResolver = new SimpleUserTypeResolver(getRequiredSession(),
CqlIdentifier.fromCql(getKeyspaceName()));
CassandraMappingContext mappingContext = new CassandraMappingContext(userTypeResolver,
SimpleTupleTypeFactory.DEFAULT);
Optional.ofNullable(this.beanClassLoader).ifPresent(mappingContext::setBeanClassLoader);
mappingContext.setInitialEntitySet(getInitialEntitySet());
CustomConversions customConversions = beanFactory.getBean(CustomConversions.class);
mappingContext.setCustomConversions(customConversions);
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
mappingContext.setCodecRegistry(getRequiredSession().getContext().getCodecRegistry());
return mappingContext;
public CassandraAdminTemplate cassandraTemplate() {
return new CassandraAdminTemplate(getRequiredSessionFactory(), requireBeanOfType(CassandraConverter.class));
}
/**
@@ -200,11 +169,35 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
}
/**
* Creates a {@link CassandraAdminTemplate}.
* Returns the initialized {@link CqlSession} instance.
*
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
*/
@Bean
public CassandraAdminTemplate cassandraTemplate() {
return new CassandraAdminTemplate(getRequiredSessionFactory(), beanFactory.getBean(CassandraConverter.class));
protected SessionFactory getRequiredSessionFactory() {
return requireBeanOfType(SessionFactory.class);
}
/**
* Creates a {@link KeyspacePopulator} to cleanup the keyspace.
*
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
*/
@Nullable
protected KeyspacePopulator keyspaceCleaner() {
return null;
}
/**
* Creates a {@link KeyspacePopulator} to initialize the keyspace.
*
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
*/
@Nullable
protected KeyspacePopulator keyspacePopulator() {
return null;
}
@Override
@@ -212,10 +205,8 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
this.beanClassLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
super.setBeanFactory(beanFactory);
protected Optional<ClassLoader> getBeanClassLoader() {
return Optional.ofNullable(this.beanClassLoader);
}
/**

View File

@@ -31,6 +31,7 @@ import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -52,6 +53,7 @@ import com.typesafe.config.ConfigFactory;
* @author Matthew T. Adams
* @author John Blum
* @author Mark Paluch
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.context.annotation.Configuration
*/
@Configuration
@@ -59,6 +61,58 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
private @Nullable BeanFactory beanFactory;
/**
* Configures a reference to the {@link BeanFactory}.
*
* @param beanFactory reference to the {@link BeanFactory}.
* @throws BeansException if the {@link BeanFactory} could not be initialized.
* @see org.springframework.beans.factory.BeanFactory
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns the configured reference to the {@link BeanFactory}.
*
* @return the configured reference to the {@link BeanFactory}.
* @throws IllegalStateException if the {@link BeanFactory} reference was not configured.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory not initialized");
return this.beanFactory;
}
/**
* Gets a required bean of the provided {@link Class type} from the {@link BeanFactory}.
*
* @param <T> {@link Class parameterized clas type} of the bean.
* @param beanType {@link Class type} of the bean.
* @return a required bean of the given {@link Class type} from the {@link BeanFactory}.
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
* @see #getBeanFactory()
*/
protected <T> T requireBeanOfType(@NonNull Class<T> beanType) {
return getBeanFactory().getBean(beanType);
}
/**
* Returns the {@link String name} of the cluster.
*
* @return the {@link String cluster name}; may be {@literal null}.
* @deprecated since 3.0, use {@link #getSessionName()} instead.
* @since 1.5
*/
@Nullable
@Deprecated
protected String getClusterName() {
return null;
}
/**
* Return the name of the keyspace to connect to.
*
@@ -67,39 +121,13 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
protected abstract String getKeyspaceName();
/**
* Returns the initialized {@link CqlSession} instance.
* Returns the local data center name used for
* {@link com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy}.
*
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected SessionFactory getRequiredSessionFactory() {
ObjectProvider<SessionFactory> beanProvider = beanFactory.getBeanProvider(SessionFactory.class);
return beanProvider.getIfAvailable(() -> new DefaultSessionFactory(beanFactory.getBean(CqlSession.class)));
}
/**
* Returns the {@link SessionBuilderConfigurer}.
*
* @return the {@link SessionBuilderConfigurer}; may be {@literal null}.
* @since 1.5
* @return the local data center name.
*/
@Nullable
protected SessionBuilderConfigurer getSessionBuilderConfigurer() {
return null;
}
/**
* Returns the cluster name.
*
* @return the cluster name; may be {@literal null}.
* @since 1.5
* @deprecated since 3.0, use {@link #getSessionName()} instead.
*/
@Nullable
@Deprecated
protected String getClusterName() {
protected String getLocalDataCenter() {
return null;
}
@@ -163,12 +191,36 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
}
/**
* Returns the local data center name used for
* {@link com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy}.
* Returns the initialized {@link CqlSession} instance.
*
* @return the local data center name.
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected String getLocalDataCenter() {
protected CqlSession getRequiredSession() {
return requireBeanOfType(CqlSession.class);
}
/**
* Returns the initialized {@link CqlSession} instance.
*
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected SessionFactory getRequiredSessionFactory() {
ObjectProvider<SessionFactory> beanProvider = getBeanFactory().getBeanProvider(SessionFactory.class);
return beanProvider.getIfAvailable(() -> new DefaultSessionFactory(requireBeanOfType(CqlSession.class)));
}
/**
* Returns the {@link SessionBuilderConfigurer}.
*
* @return the {@link SessionBuilderConfigurer}; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected SessionBuilderConfigurer getSessionBuilderConfigurer() {
return null;
}
@@ -176,9 +228,9 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
* Returns the list of startup scripts to be run after {@link #getKeyspaceCreations() keyspace creations} and after
* initialization in the {@code system} keyspace.
*
* @return the list of startup scripts, may be empty but never {@code null}.
* @deprecated since 3.0, declare a
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean.
* @return the list of startup scripts, may be {@link Collections#emptyList() empty} but never {@literal null}.
* @deprecated since 3.0; Declare a
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean instead.
*/
@Deprecated
protected List<String> getStartupScripts() {
@@ -189,28 +241,15 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
* Returns the list of shutdown scripts to be run after {@link #getKeyspaceDrops() keyspace drops} and right before
* shutdown in the {@code system} keyspace.
*
* @return the list of shutdown scripts, may be empty but never {@code null}.
* @deprecated since 3.0, declare a
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean.
* @return the list of shutdown scripts, may be {@link Collections#emptyList() empty} but never {@literal null}.
* @deprecated since 3.0; Declare a
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean instead.
*/
@Deprecated
protected List<String> getShutdownScripts() {
return Collections.emptyList();
}
/**
* Returns the initialized {@link CqlSession} instance.
*
* @return the {@link CqlSession}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected CqlSession getRequiredSession() {
Assert.state(beanFactory != null, "BeanFactory not initialized");
return beanFactory.getBean(CqlSession.class);
}
/**
* Creates a {@link CqlSessionFactoryBean} that provides a Cassandra {@link CqlSession}.
*
@@ -225,22 +264,19 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
CqlSessionFactoryBean bean = new CqlSessionFactoryBean();
bean.setContactPoints(getContactPoints());
bean.setPort(getPort());
bean.setLocalDatacenter(getLocalDataCenter());
bean.setKeyspaceCreations(getKeyspaceCreations());
bean.setKeyspaceDrops(getKeyspaceDrops());
bean.setSessionSessionBuilderConfigurer(getBuilderConfigurer());
bean.setKeyspaceName(getKeyspaceName());
bean.setKeyspaceStartupScripts(getStartupScripts());
bean.setKeyspaceShutdownScripts(getShutdownScripts());
bean.setLocalDatacenter(getLocalDataCenter());
bean.setPort(getPort());
bean.setSessionBuilderConfigurer(getSessionBuilderConfigurerWrapper());
return bean;
}
private SessionBuilderConfigurer getBuilderConfigurer() {
private SessionBuilderConfigurer getSessionBuilderConfigurerWrapper() {
SessionBuilderConfigurer configurer = getSessionBuilderConfigurer();
@@ -252,18 +288,23 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
if (StringUtils.hasText(getClusterName())) {
options.add(DefaultDriverOption.SESSION_NAME, getClusterName());
} else if (StringUtils.hasText(getSessionName())) {
}
else if (StringUtils.hasText(getSessionName())) {
options.add(DefaultDriverOption.SESSION_NAME, getSessionName());
}
CompressionType compressionType = getCompressionType();
if (compressionType != null) {
options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, compressionType);
}
ConfigFactory.invalidateCaches();
return ConfigFactory.defaultOverrides().withFallback(options.build())
.withFallback(ConfigFactory.defaultReference()).resolve();
return ConfigFactory.defaultOverrides()
.withFallback(options.build())
.withFallback(ConfigFactory.defaultReference())
.resolve();
}, DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);
@@ -288,11 +329,6 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
return new CqlTemplate(getRequiredSessionFactory());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
private static class CassandraDriverOptions {
private final Map<String, String> options = new LinkedHashMap<>();
@@ -303,21 +339,10 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
return this;
}
private CassandraDriverOptions add(DriverOption option, int value) {
return add(option, String.valueOf(value));
}
private CassandraDriverOptions add(DriverOption option, Enum<?> value) {
return add(option, value.name());
}
private CassandraDriverOptions add(DriverOption option, List<String> values) {
for (int i = 0; i < values.size(); i++) {
this.options.put(String.format("%s.%s", createKeyFor(option), i), values.get(i));
}
return this;
}
private Config build() {
return ConfigFactory.parseMap(this.options, "Environment");
}
@@ -326,5 +351,4 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
return String.format("%s.%s", DefaultDriverConfigLoader.DEFAULT_ROOT_PATH, option.getPath());
}
}
}

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.config;
import java.net.InetSocketAddress;
@@ -70,34 +69,28 @@ import com.datastax.oss.driver.api.core.CqlSessionBuilder;
public class CqlSessionFactoryBean
implements FactoryBean<CqlSession>, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
public static final int DEFAULT_PORT = 9042;
public static final String DEFAULT_CONTACT_POINTS = "localhost";
protected final Logger logger = LoggerFactory.getLogger(getClass());
private static final boolean DEFAULT_CREATE_IF_NOT_EXISTS = false;
private static final boolean DEFAULT_DROP_TABLES = false;
private static final boolean DEFAULT_DROP_UNUSED_TABLES = false;
public static final int DEFAULT_PORT = 9042;
private static final CassandraExceptionTranslator EXCEPTION_TRANSLATOR = new CassandraExceptionTranslator();
private @Nullable CqlSession systemSession;
private @Nullable CqlSession session;
public static final String CASSANDRA_SYSTEM_SESSION = "system";
public static final String DEFAULT_CONTACT_POINTS = "localhost";
private String contactPoints = DEFAULT_CONTACT_POINTS;
private int port = DEFAULT_PORT;
private @Nullable String password;
private @Nullable String username;
private @Nullable String keyspaceName;
private @Nullable String localDatacenter;
private @Nullable CassandraConverter converter;
private @Nullable SessionBuilderConfigurer sessionSessionBuilderConfigurer;
private @Nullable CqlSession session;
private @Nullable CqlSession systemSession;
private List<KeyspaceActions> keyspaceActions = new ArrayList<>();
private Set<KeyspaceActionSpecification> keyspaceSpecifications = new HashSet<>();
private List<CreateKeyspaceSpecification> keyspaceCreations = new ArrayList<>();
private List<AlterKeyspaceSpecification> keyspaceAlterations = new ArrayList<>();
private List<CreateKeyspaceSpecification> keyspaceCreations = new ArrayList<>();
private List<DropKeyspaceSpecification> keyspaceDrops = new ArrayList<>();
private List<String> keyspaceStartupScripts = new ArrayList<>();
@@ -106,15 +99,26 @@ public class CqlSessionFactoryBean
private List<String> startupScripts = Collections.emptyList();
private List<String> shutdownScripts = Collections.emptyList();
private @Nullable CassandraConverter converter;
protected final Logger logger = LoggerFactory.getLogger(getClass());
private Set<KeyspaceActionSpecification> keyspaceSpecifications = new HashSet<>();
private SchemaAction schemaAction = SchemaAction.NONE;
private @Nullable SessionBuilderConfigurer sessionBuilderConfigurer;
private String contactPoints = DEFAULT_CONTACT_POINTS;
private @Nullable String keyspaceName;
private @Nullable String localDatacenter;
private @Nullable String password;
private @Nullable String username;
/**
* Null-safe operation to determine whether the Cassandra {@link CqlSession} is connected or not.
*
* @return a boolean value indicating whether the Cassandra {@link CqlSession} is connected.
* @see Session#isClosed()
* @see com.datastax.oss.driver.api.core.session.Session#isClosed()
* @see #getObject()
*/
public boolean isConnected() {
@@ -134,6 +138,15 @@ public class CqlSessionFactoryBean
this.contactPoints = contactPoints;
}
/**
* Sets the name of the local datacenter.
*
* @param localDatacenter a String indicating the name of the local datacenter.
*/
public void setLocalDatacenter(@Nullable String localDatacenter) {
this.localDatacenter = localDatacenter;
}
/**
* Set the port for the contact points. Default is {@code 9042}, see {@link #DEFAULT_PORT}.
*
@@ -161,6 +174,82 @@ public class CqlSessionFactoryBean
this.password = password;
}
/**
* 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}.
* @deprecated Use {@link CassandraSessionFactoryBean} with
* {@link CassandraSessionFactoryBean#setConverter(CassandraConverter)} instead.
*/
@Deprecated
public void setConverter(CassandraConverter converter) {
Assert.notNull(converter, "CassandraConverter must not be null");
this.converter = converter;
}
/**
* @return the configured {@link CassandraConverter}.
*/
@Nullable
public CassandraConverter getConverter() {
return this.converter;
}
/**
* Set a {@link List} of {@link KeyspaceActions} to be executed on initialization. Keyspace actions may contain create
* and drop specifications.
*
* @param keyspaceActions the {@link List} of {@link KeyspaceActions}.
*/
public void setKeyspaceActions(List<KeyspaceActions> keyspaceActions) {
this.keyspaceActions = new ArrayList<>(keyspaceActions);
}
/**
* @return the {@link List} of {@link KeyspaceActions}.
*/
public List<KeyspaceActions> getKeyspaceActions() {
return Collections.unmodifiableList(this.keyspaceActions);
}
/**
* Set a {@link List} of {@link AlterKeyspaceSpecification alter keyspace specifications} that are executed when this
* factory is {@link #afterPropertiesSet() initialized}. {@link AlterKeyspaceSpecification Alter keyspace
* specifications} are executed on a system session with no keyspace set, before executing
* {@link #setStartupScripts(List)}.
*
* @param specifications the {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
*/
public void setKeyspaceAlterations(List<AlterKeyspaceSpecification> specifications) {
this.keyspaceAlterations = new ArrayList<>(specifications);
}
/**
* Set a {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications} that are executed when
* 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 the {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
*/
public void setKeyspaceCreations(List<CreateKeyspaceSpecification> specifications) {
this.keyspaceCreations = new ArrayList<>(specifications);
}
/**
* 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 the {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications}.
*/
public void setKeyspaceDrops(List<DropKeyspaceSpecification> specifications) {
this.keyspaceDrops = new ArrayList<>(specifications);
}
/**
* Sets the name of the Cassandra Keyspace to connect to. Passing {@literal null} will cause the Cassandra System
* Keyspace to be used.
@@ -183,23 +272,6 @@ public class CqlSessionFactoryBean
return this.keyspaceName;
}
/**
* @return the {@link List} of {@link KeyspaceActions}.
*/
public List<KeyspaceActions> getKeyspaceActions() {
return Collections.unmodifiableList(this.keyspaceActions);
}
/**
* Set a {@link List} of {@link KeyspaceActions} to be executed on initialization. Keyspace actions may contain create
* and drop specifications.
*
* @param keyspaceActions the {@link List} of {@link KeyspaceActions}.
*/
public void setKeyspaceActions(List<KeyspaceActions> keyspaceActions) {
this.keyspaceActions = new ArrayList<>(keyspaceActions);
}
/**
* @param keyspaceSpecifications The {@link KeyspaceActionSpecification} to set.
*/
@@ -208,38 +280,10 @@ public class CqlSessionFactoryBean
}
/**
* Set a {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications} that are executed when
* 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 the {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
* @return the {@link KeyspaceActionSpecification} associated with this factory.
*/
public void setKeyspaceCreations(List<CreateKeyspaceSpecification> specifications) {
this.keyspaceCreations = new ArrayList<>(specifications);
}
/**
* Set a {@link List} of {@link AlterKeyspaceSpecification alter keyspace specifications} that are executed when this
* factory is {@link #afterPropertiesSet() initialized}. {@link AlterKeyspaceSpecification Alter keyspace
* specifications} are executed on a system session with no keyspace set, before executing
* {@link #setStartupScripts(List)}.
*
* @param specifications the {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
*/
public void setKeyspaceAlterations(List<AlterKeyspaceSpecification> specifications) {
this.keyspaceAlterations = new ArrayList<>(specifications);
}
/**
* 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 the {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications}.
*/
public void setKeyspaceDrops(List<DropKeyspaceSpecification> specifications) {
this.keyspaceDrops = new ArrayList<>(specifications);
public Set<KeyspaceActionSpecification> getKeyspaceSpecifications() {
return Collections.unmodifiableSet(this.keyspaceSpecifications);
}
/**
@@ -265,19 +309,37 @@ public class CqlSessionFactoryBean
}
/**
* @return the {@link KeyspaceActionSpecification} associated with this factory.
* @return the {@link CassandraMappingContext}.
*/
public Set<KeyspaceActionSpecification> getKeyspaceSpecifications() {
return Collections.unmodifiableSet(this.keyspaceSpecifications);
protected CassandraMappingContext getMappingContext() {
CassandraConverter converter = getConverter();
Assert.state(converter != null, "CassandraConverter was not properly initialized");
return converter.getMappingContext();
}
/**
* Sets the name of the local datacenter.
* Set the {@link SchemaAction}.
*
* @param localDatacenter a String indicating the name of the local datacenter.
* @param schemaAction must not be {@literal null}.
* @deprecated Use {@link CassandraSessionFactoryBean} with
* {@link CassandraSessionFactoryBean#setSchemaAction(SchemaAction)} instead.
*/
public void setLocalDatacenter(@Nullable String localDatacenter) {
this.localDatacenter = localDatacenter;
@Deprecated
public void setSchemaAction(SchemaAction schemaAction) {
Assert.notNull(schemaAction, "SchemaAction must not be null");
this.schemaAction = schemaAction;
}
/**
* @return the {@link SchemaAction}.
*/
public SchemaAction getSchemaAction() {
return this.schemaAction;
}
/**
@@ -285,7 +347,7 @@ public class CqlSessionFactoryBean
*
* @return a reference to the connected Cassandra {@link CqlSession}.
* @throws IllegalStateException if the Cassandra {@link CqlSession} was not properly initialized.
* @see Session
* @see com.datastax.oss.driver.api.core.CqlSession
*/
protected CqlSession getSession() {
@@ -300,10 +362,10 @@ public class CqlSessionFactoryBean
* Sets the {@link SessionBuilderConfigurer} to configure the
* {@link com.datastax.oss.driver.api.core.session.SessionBuilder}.
*
* @param sessionSessionBuilderConfigurer
* @param sessionBuilderConfigurer
*/
public void setSessionSessionBuilderConfigurer(@Nullable SessionBuilderConfigurer sessionSessionBuilderConfigurer) {
this.sessionSessionBuilderConfigurer = sessionSessionBuilderConfigurer;
public void setSessionBuilderConfigurer(@Nullable SessionBuilderConfigurer sessionBuilderConfigurer) {
this.sessionBuilderConfigurer = sessionBuilderConfigurer;
}
/**
@@ -354,64 +416,6 @@ public class CqlSessionFactoryBean
return Collections.unmodifiableList(this.shutdownScripts);
}
/**
* 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}.
* @deprecated Use {@link CassandraSessionFactoryBean} with
* {@link CassandraSessionFactoryBean#setConverter(CassandraConverter)} instead.
*/
@Deprecated
public void setConverter(CassandraConverter converter) {
Assert.notNull(converter, "CassandraConverter must not be null");
this.converter = converter;
}
/**
* @return the {@link CassandraConverter}.
*/
@Nullable
public CassandraConverter getConverter() {
return this.converter;
}
/**
* @return the {@link CassandraMappingContext}.
*/
protected CassandraMappingContext getMappingContext() {
CassandraConverter converter = getConverter();
Assert.state(converter != null, "CassandraConverter was not properly initialized");
return converter.getMappingContext();
}
/**
* 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");
this.schemaAction = schemaAction;
}
/**
* @return the {@link SchemaAction}.
*/
public SchemaAction getSchemaAction() {
return this.schemaAction;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
@@ -420,35 +424,65 @@ public class CqlSessionFactoryBean
public void afterPropertiesSet() {
CqlSessionBuilder sessionBuilder = buildBuilder();
this.systemSession = buildSystemSession(sessionBuilder);
initializeCluster(this.systemSession);
this.session = buildSession(sessionBuilder);
executeScripts(getStartupScripts().stream(), this.session);
executeCql(getStartupScripts().stream(), this.session);
performSchemaAction();
this.systemSession.refreshSchema();
this.session.refreshSchema();
}
/**
* Build the system session.
*
* @param sessionBuilder
* @return
*/
protected CqlSession buildSystemSession(CqlSessionBuilder sessionBuilder) {
return sessionBuilder.withKeyspace("system").build();
protected CqlSessionBuilder buildBuilder() {
Assert.hasText(this.contactPoints, "At least one server is required");
CqlSessionBuilder sessionBuilder = CqlSession.builder();
StringUtils.commaDelimitedListToSet(this.contactPoints).forEach(host ->
sessionBuilder.addContactPoint(InetSocketAddress.createUnresolved(host, this.port)));
if (StringUtils.hasText(this.username)) {
sessionBuilder.withAuthCredentials(this.username, this.password);
}
if (StringUtils.hasText(this.localDatacenter)) {
sessionBuilder.withLocalDatacenter(this.localDatacenter);
}
return this.sessionBuilderConfigurer != null
? this.sessionBuilderConfigurer.configure(sessionBuilder)
: sessionBuilder;
}
/**
* Build the keyspace session.
* Build the Cassandra {@link CqlSession System Session}.
*
* @param sessionBuilder
* @return
* @param sessionBuilder {@link CqlSessionBuilder} used to a build a Cassandra {@link CqlSession}.
* @return the built Cassandra {@link CqlSession System Session}.
* @see com.datastax.oss.driver.api.core.CqlSessionBuilder
* @see com.datastax.oss.driver.api.core.CqlSession
*/
protected CqlSession buildSystemSession(CqlSessionBuilder sessionBuilder) {
return sessionBuilder.withKeyspace(CASSANDRA_SYSTEM_SESSION).build();
}
/**
* Build a {@link CqlSession Session} to the user-defined {@literal Keyspace} or the default {@literal Keyspace}
* if the user did not specify a {@literal Keyspace} by {@link String name}.
*
* @param sessionBuilder {@link CqlSessionBuilder} used to a build a Cassandra {@link CqlSession}.
* @return the built {@link CqlSession} to the user-defined {@literal Keyspace}.
* @see com.datastax.oss.driver.api.core.CqlSessionBuilder
* @see com.datastax.oss.driver.api.core.CqlSession
*/
protected CqlSession buildSession(CqlSessionBuilder sessionBuilder) {
if (StringUtils.hasText(getKeyspaceName())) {
sessionBuilder.withKeyspace(getKeyspaceName());
}
@@ -456,82 +490,43 @@ public class CqlSessionFactoryBean
return sessionBuilder.build();
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() {
if (session != null) {
executeScripts(getShutdownScripts().stream(), this.session);
executeSpecsAndScripts(keyspaceDrops, keyspaceShutdownScripts, this.systemSession);
closeSystemSession();
closeSession();
}
}
/**
* Close the regular session object.
*/
protected void closeSession() {
session.close();
}
/**
* Close the system session object.
*/
protected void closeSystemSession() {
systemSession.close();
}
protected CqlSessionBuilder buildBuilder() {
Assert.hasText(this.contactPoints, "At least one server is required");
CqlSessionBuilder builder = CqlSession.builder();
StringUtils.commaDelimitedListToSet(this.contactPoints).stream().forEach(host -> {
builder.addContactPoint(InetSocketAddress.createUnresolved(host, this.port));
});
if (StringUtils.hasText(this.username)) {
builder.withAuthCredentials(this.username, this.password);
}
if (StringUtils.hasText(this.localDatacenter)) {
builder.withLocalDatacenter(this.localDatacenter);
}
if (this.sessionSessionBuilderConfigurer != null) {
return this.sessionSessionBuilderConfigurer.configure(builder);
}
return builder;
}
private void initializeCluster(CqlSession session) {
generateSpecificationsFromFactoryDeclarations();
generateSpecificationsFromFactoryBeanDeclarations();
List<KeyspaceActionSpecification> startupSpecifications = new ArrayList<>(
this.keyspaceCreations.size() + this.keyspaceAlterations.size());
List<KeyspaceActionSpecification> keyspaceStartupSpecifications =
new ArrayList<>(this.keyspaceCreations.size() + this.keyspaceAlterations.size());
startupSpecifications.addAll(this.keyspaceCreations);
startupSpecifications.addAll(this.keyspaceAlterations);
keyspaceStartupSpecifications.addAll(this.keyspaceCreations);
keyspaceStartupSpecifications.addAll(this.keyspaceAlterations);
executeSpecsAndScripts(startupSpecifications, this.keyspaceStartupScripts, session);
executeSpecificationsAndScripts(keyspaceStartupSpecifications, this.keyspaceStartupScripts, session);
}
private void executeSpecsAndScripts(List<? extends KeyspaceActionSpecification> keyspaceActionSpecifications,
List<String> scripts, CqlSession session) {
/**
* Evaluates the contents of all the {@link KeyspaceActionSpecificationFactoryBean}s
* and generates the proper {@link KeyspaceActionSpecification}s from them.
*/
private void generateSpecificationsFromFactoryBeanDeclarations() {
if (!CollectionUtils.isEmpty(keyspaceActionSpecifications) || !CollectionUtils.isEmpty(scripts)) {
generateSpecifications(this.keyspaceSpecifications);
this.keyspaceActions.forEach(actions -> generateSpecifications(actions.getActions()));
}
Stream<String> keyspaceActions = keyspaceActionSpecifications.stream().map(this::toCql);
private void generateSpecifications(Collection<KeyspaceActionSpecification> specifications) {
executeScripts(Stream.concat(keyspaceActions, scripts.stream()), session);
}
specifications.forEach(specification -> {
if (specification instanceof AlterKeyspaceSpecification) {
this.keyspaceAlterations.add((AlterKeyspaceSpecification) specification);
}
else if (specification instanceof CreateKeyspaceSpecification) {
this.keyspaceCreations.add((CreateKeyspaceSpecification) specification);
}
else if (specification instanceof DropKeyspaceSpecification) {
this.keyspaceDrops.add((DropKeyspaceSpecification) specification);
}
});
}
/**
@@ -567,27 +562,28 @@ public class CqlSessionFactoryBean
* 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.
* @param dropUnused {@literal true} to drop unused types/tables (i.e. types/tables not known to be used by
* the {@link CassandraMappingContext}).
* @param ifNotExists {@literal true} to perform fail-safe creations by adding {@code IF NOT EXISTS}
* to each creation statement.
*/
protected void createTables(boolean drop, boolean dropUnused, boolean ifNotExists) {
CassandraAdminTemplate adminTemplate = new CassandraAdminTemplate(this.session, converter);
CassandraAdminTemplate adminTemplate = new CassandraAdminTemplate(this.session, this.converter);
performSchemaActions(drop, dropUnused, ifNotExists, adminTemplate);
}
private void performSchemaActions(boolean drop, boolean dropUnused, boolean ifNotExists,
CassandraAdminOperations adminOperations) {
CassandraPersistentEntitySchemaCreator schemaCreator = new CassandraPersistentEntitySchemaCreator(
getMappingContext(), adminOperations);
CassandraPersistentEntitySchemaCreator schemaCreator =
new CassandraPersistentEntitySchemaCreator(getMappingContext(), adminOperations);
if (drop) {
CassandraPersistentEntitySchemaDropper schemaDropper = new CassandraPersistentEntitySchemaDropper(
getMappingContext(), adminOperations);
CassandraPersistentEntitySchemaDropper schemaDropper =
new CassandraPersistentEntitySchemaDropper(getMappingContext(), adminOperations);
schemaDropper.dropTables(dropUnused);
schemaDropper.dropUserTypes(dropUnused);
@@ -598,6 +594,35 @@ public class CqlSessionFactoryBean
schemaCreator.createIndexes(ifNotExists);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() {
if (this.session != null) {
executeCql(getShutdownScripts().stream(), this.session);
executeSpecificationsAndScripts(this.keyspaceDrops, this.keyspaceShutdownScripts, this.systemSession);
closeSession();
closeSystemSession();
}
}
/**
* Close the regular session object.
*/
protected void closeSession() {
this.session.close();
}
/**
* Close the system session object.
*/
protected void closeSystemSession() {
this.systemSession.close();
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
@@ -626,52 +651,54 @@ public class CqlSessionFactoryBean
}
/**
* Executes the given Cassandra CQL scripts. The {@link CqlSession} must be connected when this method is called.
* Executes the given, raw Cassandra CQL scripts.
*
* The {@link CqlSession} must be connected when this method is called.
*
* @see com.datastax.oss.driver.api.core.CqlSession#execute(String)
*/
private void executeScripts(Stream<String> scripts, CqlSession session) {
private void executeCql(Stream<String> cql, CqlSession session) {
scripts.forEach(script -> {
logger.info("executing raw CQL [{}]", script);
session.execute(script);
cql.forEach(query -> {
this.logger.info("Executing CQL [{}]", query);
session.execute(query);
});
}
private void executeSpecificationsAndScripts(List<? extends KeyspaceActionSpecification> keyspaceActionSpecifications,
List<String> keyspaceCqlScripts, CqlSession session) {
if (!CollectionUtils.isEmpty(keyspaceActionSpecifications) || !CollectionUtils.isEmpty(keyspaceCqlScripts)) {
Stream<String> keyspaceActionSpecificationsStream = keyspaceActionSpecifications.stream().map(this::toCql);
Stream<String> keyspaceCqlScriptsStream = keyspaceCqlScripts.stream();
Stream<String> cql = Stream.concat(keyspaceActionSpecificationsStream, keyspaceCqlScriptsStream);
executeCql(cql, session);
}
}
/**
* Evaluates the contents of all the KeyspaceSpecificationFactoryBean and generates the proper KeyspaceSpecification
* from them.
* Converts the {@link KeyspaceActionSpecification} to {@link String CQL}.
*
* @param specification {@link KeyspaceActionSpecification} to convert to {@link String CQL}.
* @return a {@link String} containing the CQL for the given {@link KeyspaceActionSpecification}.
* @see org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification
*/
private void generateSpecificationsFromFactoryDeclarations() {
generateSpecifications(this.keyspaceSpecifications);
this.keyspaceActions.forEach(actions -> generateSpecifications(actions.getActions()));
}
private void generateSpecifications(Collection<KeyspaceActionSpecification> specifications) {
specifications.forEach(keyspaceActionSpecification -> {
if (keyspaceActionSpecification instanceof AlterKeyspaceSpecification) {
this.keyspaceAlterations.add((AlterKeyspaceSpecification) keyspaceActionSpecification);
} else if (keyspaceActionSpecification instanceof CreateKeyspaceSpecification) {
this.keyspaceCreations.add((CreateKeyspaceSpecification) keyspaceActionSpecification);
} else if (keyspaceActionSpecification instanceof DropKeyspaceSpecification) {
this.keyspaceDrops.add((DropKeyspaceSpecification) keyspaceActionSpecification);
}
});
}
private String toCql(KeyspaceActionSpecification specification) {
if (specification instanceof AlterKeyspaceSpecification) {
return new AlterKeyspaceCqlGenerator((AlterKeyspaceSpecification) specification).toCql();
} else if (specification instanceof CreateKeyspaceSpecification) {
}
else if (specification instanceof CreateKeyspaceSpecification) {
return new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) specification).toCql();
} else if (specification instanceof DropKeyspaceSpecification) {
}
else if (specification instanceof DropKeyspaceSpecification) {
return new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) specification).toCql();
}
throw new IllegalArgumentException(
"Unsupported specification type: " + ClassUtils.getQualifiedName(specification.getClass()));
throw new IllegalArgumentException(String.format("Unsupported specification type: %s",
ClassUtils.getQualifiedName(specification.getClass())));
}
@Nullable

View File

@@ -16,25 +16,26 @@
package org.springframework.data.cassandra.config;
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import com.datastax.oss.driver.api.core.session.SessionBuilder;
/**
* Configuration callback class to allow a user to apply additional configuration logic to the {@link SessionBuilder}.
* Configuration callback to allow users to implement and apply additional configuration logic to
* the {@link CqlSessionBuilder}.
*
* @author John Blum
* @author Mark Paluch
* @see com.datastax.oss.driver.api.core.CqlSessionBuilder
* @since 3.0
* @see com.datastax.oss.driver.api.core.CqlSession
*/
@FunctionalInterface
public interface SessionBuilderConfigurer {
/**
* Apply addition configuration to the {@link SessionBuilder}.
* Apply additional configuration to the Cassandra {@link CqlSessionBuilder}.
*
* @param sessionBuilder {@link SessionBuilder} to configure.
* @return the argument to the {@code sessionBuilder} parameter.
* @see SessionBuilder
* @param sessionBuilder {@link CqlSessionBuilder} to configure.
* @return the {@link CqlSessionBuilder} or a decorated {@link CqlSessionBuilder} as required by the caller.
* @see com.datastax.oss.driver.api.core.CqlSessionBuilder
*/
CqlSessionBuilder configure(CqlSessionBuilder sessionBuilder);
}

View File

@@ -46,51 +46,15 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
protected static final boolean DEFAULT_DROP_TABLES = false;
protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false;
private CqlSession session;
private @Nullable KeyspacePopulator keyspacePopulator;
private @Nullable KeyspacePopulator keyspaceCleaner;
private CassandraConverter converter;
private CqlSession session;
private @Nullable KeyspacePopulator keyspaceCleaner;
private @Nullable KeyspacePopulator keyspacePopulator;
private SchemaAction schemaAction = SchemaAction.NONE;
/**
* Set the {@link CqlSession} to use.
*
* @param session must not be {@literal null}.
*/
public void setSession(CqlSession session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
/**
* Set the {@link KeyspacePopulator} to execute during the bean initialization phase. The
* {@link KeyspacePopulator#populate(CqlSession) KeyspacePopulator} is invoked before creating
* {@link #setSchemaAction(SchemaAction) the schema}.
*
* @param keyspacePopulator the {@link KeyspacePopulator} to use during initialization.
* @see #setKeyspaceCleaner
*/
public void setKeyspacePopulator(@Nullable 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 cleanup.
* @see #setKeyspacePopulator
*/
public void setKeyspaceCleaner(@Nullable 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}.
@@ -104,6 +68,29 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
this.converter = converter;
}
/**
* 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 cleanup.
* @see #setKeyspacePopulator
*/
public void setKeyspaceCleaner(@Nullable KeyspacePopulator keyspaceCleaner) {
this.keyspaceCleaner = keyspaceCleaner;
}
/**
* Set the {@link KeyspacePopulator} to execute during the bean initialization phase. The
* {@link KeyspacePopulator#populate(CqlSession) KeyspacePopulator} is invoked before creating
* {@link #setSchemaAction(SchemaAction) the schema}.
*
* @param keyspacePopulator the {@link KeyspacePopulator} to use during initialization.
* @see #setKeyspaceCleaner
*/
public void setKeyspacePopulator(@Nullable KeyspacePopulator keyspacePopulator) {
this.keyspacePopulator = keyspacePopulator;
}
/**
* Set the {@link SchemaAction}.
*
@@ -116,11 +103,24 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
this.schemaAction = schemaAction;
}
/**
* Set the {@link CqlSession} to use.
*
* @param session must not be {@literal null}.
*/
public void setSession(CqlSession session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
/*
* (non-Javadoc)
* @see org.springframework.cassandra.config.CassandraCqlSessionFactoryBean#afterPropertiesSet()
*/
@Override
@SuppressWarnings("all")
public void afterPropertiesSet() throws Exception {
Assert.state(this.session != null, "Session was not properly initialized");
@@ -138,7 +138,14 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
}
@Override
protected SessionFactory createInstance() {
return new DefaultSessionFactory(this.session);
}
@Override
@SuppressWarnings("all")
public void destroy() throws Exception {
if (this.keyspaceCleaner != null) {
this.keyspaceCleaner.populate(getObject().getSession());
}
@@ -150,11 +157,6 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
return SessionFactory.class;
}
@Override
protected SessionFactory createInstance() {
return new DefaultSessionFactory(session);
}
/**
* Perform the configure {@link SchemaAction} using {@link CassandraMappingContext} metadata.
*/
@@ -197,17 +199,18 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
performSchemaActions(drop, dropUnused, ifNotExists);
}
@SuppressWarnings("all")
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);
CassandraPersistentEntitySchemaCreator schemaCreator =
new CassandraPersistentEntitySchemaCreator(this.converter.getMappingContext(), adminOperations);
if (drop) {
CassandraPersistentEntitySchemaDropper schemaDropper = new CassandraPersistentEntitySchemaDropper(
this.converter.getMappingContext(), adminOperations);
CassandraPersistentEntitySchemaDropper schemaDropper =
new CassandraPersistentEntitySchemaDropper(this.converter.getMappingContext(), adminOperations);
schemaDropper.dropTables(dropUnused);
schemaDropper.dropUserTypes(dropUnused);