Skip to content

Commit

Permalink
Polish 'Allow spring.data.cassandra.config file to override default v…
Browse files Browse the repository at this point in the history
…alues'

See gh-31238
  • Loading branch information
philwebb committed Jun 23, 2022
1 parent 1c7d998 commit 904feb2
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 86 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
Expand All @@ -19,6 +19,7 @@
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -63,13 +64,23 @@
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Steffen F. Qvistgaard
* @author Ittay Stern
* @since 1.3.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ CqlSession.class })
@EnableConfigurationProperties(CassandraProperties.class)
public class CassandraAutoConfiguration {

private static final Config SPRING_BOOT_DEFAULTS;
static {
CassandraDriverOptions options = new CassandraDriverOptions();
options.add(DefaultDriverOption.CONTACT_POINTS, Collections.singletonList("127.0.0.1:9042"));
options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, "none");
options.add(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, (int) Duration.ofSeconds(5).toMillis());
SPRING_BOOT_DEFAULTS = options.build();
}

@Bean
@ConditionalOnMissingBean
@Lazy
Expand Down Expand Up @@ -118,43 +129,41 @@ public DriverConfigLoader cassandraDriverConfigLoader(CassandraProperties proper
}

private Config cassandraConfiguration(CassandraProperties properties) {
Config config = mapConfig(properties);
Resource configFile = properties.getConfig();
return (configFile != null) ? applyDefaultFallback(config.withFallback(loadConfig(configFile)))
: applyDefaultFallback(config);
}

private Config applyDefaultFallback(Config config) {
ConfigFactory.invalidateCaches();
return ConfigFactory.defaultOverrides().withFallback(config)
.withFallback(mapConfig(CassandraProperties.defaults())).withFallback(ConfigFactory.defaultReference())
.resolve();
Config config = ConfigFactory.defaultOverrides();
config = config.withFallback(mapConfig(properties));
if (properties.getConfig() != null) {
config = config.withFallback(loadConfig(properties.getConfig()));
}
config = config.withFallback(SPRING_BOOT_DEFAULTS);
config = config.withFallback(ConfigFactory.defaultReference());
return config.resolve();
}

private Config loadConfig(Resource config) {
private Config loadConfig(Resource resource) {
try {
return ConfigFactory.parseURL(config.getURL());
return ConfigFactory.parseURL(resource.getURL());
}
catch (IOException ex) {
throw new IllegalStateException("Failed to load cassandra configuration from " + config, ex);
throw new IllegalStateException("Failed to load cassandra configuration from " + resource, ex);
}
}

private Config mapConfig(CassandraProperties properties) {
CassandraDriverOptions options = new CassandraDriverOptions();
PropertyMapper map = PropertyMapper.get();
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(properties.getSessionName()).whenHasText()
.to((sessionName) -> options.add(DefaultDriverOption.SESSION_NAME, sessionName));
map.from(properties::getUsername).whenNonNull()
map.from(properties::getUsername)
.to((username) -> options.add(DefaultDriverOption.AUTH_PROVIDER_USER_NAME, username)
.add(DefaultDriverOption.AUTH_PROVIDER_PASSWORD, properties.getPassword()));
map.from(properties::getCompression).whenNonNull()
map.from(properties::getCompression)
.to((compression) -> options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, compression));
mapConnectionOptions(properties, options);
mapPoolingOptions(properties, options);
mapRequestOptions(properties, options);
mapControlConnectionOptions(properties, options);
map.from(mapContactPoints(properties)).whenNonNull()
map.from(mapContactPoints(properties))
.to((contactPoints) -> options.add(DefaultDriverOption.CONTACT_POINTS, contactPoints));
map.from(properties.getLocalDatacenter()).whenHasText().to(
(localDatacenter) -> options.add(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, localDatacenter));
Expand Down Expand Up @@ -211,9 +220,12 @@ private void mapControlConnectionOptions(CassandraProperties properties, Cassand
}

private List<String> mapContactPoints(CassandraProperties properties) {
List<String> contactPoints = properties.getContactPoints();
return (contactPoints == null) ? null : contactPoints.stream()
.map((candidate) -> formatContactPoint(candidate, properties.getPort())).collect(Collectors.toList());
if (properties.getContactPoints() != null) {
return properties.getContactPoints().stream()
.map((candidate) -> formatContactPoint(candidate, properties.getPort()))
.collect(Collectors.toList());
}
return null;
}

private String formatContactPoint(String candidate, int port) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package org.springframework.boot.autoconfigure.cassandra;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
Expand All @@ -38,16 +36,6 @@
@ConfigurationProperties(prefix = "spring.data.cassandra")
public class CassandraProperties {

static CassandraProperties defaults() {
CassandraProperties properties = new CassandraProperties();

properties.setContactPoints(new ArrayList<>(Collections.singleton("127.0.0.1:9042")));
properties.setCompression(Compression.NONE);
properties.getControlconnection().setTimeout(Duration.ofSeconds(5));

return properties;
}

/**
* Location of the configuration file to use.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@
"name": "spring.data.cassandra.connection.init-query-timeout",
"defaultValue": "5s"
},
{
"name": "spring.data.cassandra.controlconnection.timeout",
"defaultValue": "5s"
},
{
"name": "spring.data.cassandra.contact-points",
"defaultValue": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
Expand All @@ -18,7 +18,6 @@

import java.time.Duration;
import java.util.Collections;
import java.util.List;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
Expand All @@ -30,7 +29,6 @@
import com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler;
import com.datastax.oss.driver.internal.core.session.throttling.PassThroughRequestThrottler;
import com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;
Expand All @@ -46,6 +44,7 @@
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Ittay Stern
*/
class CassandraAutoConfigurationTests {

Expand Down Expand Up @@ -247,41 +246,25 @@ void driverConfigLoaderWithConfigComplementSettings() {
});
}

@Test // gh-31025
@Test // gh-31238
void driverConfigLoaderWithConfigOverridesDefaults() {
String configLocation = "org/springframework/boot/autoconfigure/cassandra/override-defaults.conf";
this.contextRunner.withPropertyValues("spring.data.cassandra.config=" + configLocation).run((context) -> {
assertThat(context).hasSingleBean(DriverConfigLoader.class);

SoftAssertions softly = new SoftAssertions();

softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo("advanced session");

softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getDuration(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofSeconds(2)); // default

softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getStringList(DefaultDriverOption.CONTACT_POINTS)).isEqualTo(Collections.singletonList("1.2.3.4:5678"));
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getBoolean(DefaultDriverOption.RESOLVE_CONTACT_POINTS)).isFalse();
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getInt(DefaultDriverOption.REQUEST_PAGE_SIZE)).isEqualTo(11);
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)).isEqualTo("datacenter1");

softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS)).isEqualTo(22);
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND)).isEqualTo(33);
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(44);
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getDuration(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT)).isEqualTo(Duration.ofMillis(5555));
softly.assertThat(context.getBean(DriverConfigLoader.class).getInitialConfig().getDefaultProfile()
.getString(DefaultDriverOption.PROTOCOL_COMPRESSION)).isEqualTo("SNAPPY");

softly.assertAll();
DriverExecutionProfile actual = context.getBean(DriverConfigLoader.class).getInitialConfig()
.getDefaultProfile();
assertThat(actual.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo("advanced session");
assertThat(actual.getDuration(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofSeconds(2));
assertThat(actual.getStringList(DefaultDriverOption.CONTACT_POINTS))
.isEqualTo(Collections.singletonList("1.2.3.4:5678"));
assertThat(actual.getBoolean(DefaultDriverOption.RESOLVE_CONTACT_POINTS)).isFalse();
assertThat(actual.getInt(DefaultDriverOption.REQUEST_PAGE_SIZE)).isEqualTo(11);
assertThat(actual.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)).isEqualTo("datacenter1");
assertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS)).isEqualTo(22);
assertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND)).isEqualTo(33);
assertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(44);
assertThat(actual.getDuration(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT))
.isEqualTo(Duration.ofMillis(5555));
assertThat(actual.getString(DefaultDriverOption.PROTOCOL_COMPRESSION)).isEqualTo("SNAPPY");
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
datastax-java-driver {
basic {
session-name = advanced session
load-balancing-policy {
local-datacenter = datacenter1
}
request.page-size = 11
contact-points = [ "1.2.3.4:5678" ]
}
advanced {
throttler {
max-concurrent-requests = 22
max-requests-per-second = 33
max-queue-size = 44
}
control-connection.timeout = 5555
protocol.compression = SNAPPY
resolve-contact-points = false
}
basic {
session-name = advanced session
load-balancing-policy {
local-datacenter = datacenter1
}
request.page-size = 11
contact-points = [ "1.2.3.4:5678" ]
}
advanced {
throttler {
max-concurrent-requests = 22
max-requests-per-second = 33
max-queue-size = 44
}
control-connection.timeout = 5555
protocol.compression = SNAPPY
resolve-contact-points = false
}
}

0 comments on commit 904feb2

Please sign in to comment.