DATACASS-721 - Refactor codebase around uses of the new DataStax 4.x Driver API.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user