DATACASS-798 - Introduce CassandraDriverOptionsConfigurer and allow specifying a configuration file.

We now allow configuring a DriverConfigLoaderBuilderConfigurer and specifying a driver configuration file through AbstractSessionConfiguration to improve configuration possibilities. The DriverConfigLoaderBuilderConfigurer gets applied after applying the configuration to DriverConfigLoaderBuilder. The driver config file acts as a fallback config if the configuration property cannot be looked up from system properties or from the configuration in DriverConfigLoaderBuilder.
This commit is contained in:
Mark Paluch
2020-11-18 10:29:15 +01:00
parent b28cba10f9
commit 7f3508e0e0
4 changed files with 193 additions and 6 deletions

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.config;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -26,6 +28,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
@@ -224,6 +227,33 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
return null;
}
/**
* Returns the {@link DriverConfigLoaderBuilderConfigurer}. The configuration gets applied after applying
* {@link System#getProperties() System Properties} config overrides and before
* {@link #getDriverConfigurationResource() the driver config file}.
*
* @return the {@link DriverConfigLoaderBuilderConfigurer}; may be {@literal null}.
* @since 3.1.2
*/
@Nullable
protected DriverConfigLoaderBuilderConfigurer getDriverConfigLoaderBuilderConfigurer() {
return null;
}
/**
* Returns the {@link Resource} pointing to a driver configuration file. The configuration file is applied after
* applying {@link System#getProperties() System Properties} and the configuration built by this configuration class.
*
* @return the {@link Resource}; may be {@literal null} if none provided.
* @since 3.1.2
* @see <a href="https://docs.datastax.com/en/developer/java-driver/4.9/manual/core/configuration/">Driver
* Configuration</a>
*/
@Nullable
protected Resource getDriverConfigurationResource() {
return null;
}
/**
* Returns the list of CQL scripts to be run on startup after {@link #getKeyspaceCreations() Keyspace creations}
* and after initialization of the {@literal System} Keyspace.
@@ -280,7 +310,9 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
private SessionBuilderConfigurer getSessionBuilderConfigurerWrapper() {
SessionBuilderConfigurer configurer = getSessionBuilderConfigurer();
SessionBuilderConfigurer sessionConfigurer = getSessionBuilderConfigurer();
DriverConfigLoaderBuilderConfigurer driverConfigLoaderConfigurer = getDriverConfigLoaderBuilderConfigurer();
Resource driverConfigFile = getDriverConfigurationResource();
return sessionBuilder -> {
@@ -302,16 +334,30 @@ public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
ConfigFactory.invalidateCaches();
return ConfigFactory.defaultOverrides() //
.withFallback(options.build()) //
.withFallback(ConfigFactory.defaultReference());
Config config = ConfigFactory.defaultOverrides() //
.withFallback(options.build());
if (driverConfigFile != null) {
try {
config = config
.withFallback(ConfigFactory.parseReader(new InputStreamReader(driverConfigFile.getInputStream())));
} catch (IOException e) {
throw new IllegalStateException(String.format("Cannot parse driver config file %s", driverConfigFile), e);
}
}
return config.withFallback(ConfigFactory.defaultReference());
}, DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);
if (driverConfigLoaderConfigurer != null) {
driverConfigLoaderConfigurer.configure(builder);
}
sessionBuilder.withConfigLoader(builder.build());
if (configurer != null) {
return configurer.configure(sessionBuilder);
if (sessionConfigurer != null) {
return sessionConfigurer.configure(sessionBuilder);
}
return sessionBuilder;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.config;
import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;
/**
* Callback interface that can be implemented by beans wishing to customize the
* {@link ProgrammaticDriverConfigLoaderBuilder} via a {@link DriverConfigLoaderBuilderConfigurer} whilst retaining
* default configuration.
*
* @author Mark Paluch
* @since 3.1.2
*/
public interface DriverConfigLoaderBuilderConfigurer {
/**
* Customize the {@linkplain ProgrammaticDriverConfigLoaderBuilder DriverConfigLoader builder}.
*
* @param builder the builder to customize
*/
void configure(ProgrammaticDriverConfigLoaderBuilder builder);
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.config;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.cassandra.support.CassandraConnectionProperties;
import org.springframework.data.cassandra.test.util.CassandraExtension;
import org.springframework.lang.Nullable;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
/**
* Unit tests for {@link AbstractSessionConfiguration}.
*
* @author Mark Paluch
*/
@ExtendWith(CassandraExtension.class)
class AbstractSessionConfigurationIntegrationTests {
@Test
void shouldApplyDriverConfigLoaderBuilderConfigurer() {
MySessionConfiguration configuration = new MySessionConfiguration();
CqlSessionFactoryBean bean = configuration.cassandraSession();
bean.afterPropertiesSet();
CqlSession session = bean.getObject();
assertThat(session.getContext().getConfig().getProfile("foo")).isNotNull();
assertThat(session.getContext().getConfig().getProfiles()).doesNotContainKeys("bar");
}
@Test
void shouldApplyConfigurationFile() {
MySessionConfiguration configuration = new MySessionConfiguration();
CqlSessionFactoryBean bean = configuration.cassandraSession();
bean.afterPropertiesSet();
CqlSession session = bean.getObject();
assertThat(session.getContext().getConfig().getProfile("oltp")).isNotNull();
assertThat(session.getContext().getConfig().getProfiles()).doesNotContainKeys("bar");
}
static class MySessionConfiguration extends AbstractSessionConfiguration {
@Override
protected String getKeyspaceName() {
return "system";
}
@Nullable
@Override
protected String getLocalDataCenter() {
return "datacenter1";
}
@Override
protected int getPort() {
return new CassandraConnectionProperties().getCassandraPort();
}
@Nullable
@Override
protected DriverConfigLoaderBuilderConfigurer getDriverConfigLoaderBuilderConfigurer() {
return it -> {
it.startProfile("foo").withString(DefaultDriverOption.SESSION_NAME, "hello-world").endProfile();
};
}
@Nullable
@Override
protected Resource getDriverConfigurationResource() {
return new ClassPathResource("application.conf");
}
}
}

View File

@@ -11,6 +11,13 @@
# This file is in HOCON format, see https://github.com/typesafehub/config/blob/master/HOCON.md.
datastax-java-driver {
profiles {
oltp {
basic.request.timeout = 100 milliseconds
basic.request.consistency = ONE
}
}
basic.load-balancing-policy {
class = DcInferringLoadBalancingPolicy
}