com.datastax.oss.driver.internal.core.config.typesafe.DefaultProgrammaticDriverConfigLoaderBuilder Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.datastax.oss.driver.internal.core.config.typesafe;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.datastax.oss.driver.api.core.config.DriverOption;
import com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import net.jcip.annotations.NotThreadSafe;
@NotThreadSafe
public class DefaultProgrammaticDriverConfigLoaderBuilder
implements ProgrammaticDriverConfigLoaderBuilder {
public static final Supplier DEFAULT_FALLBACK_SUPPLIER =
() ->
ConfigFactory.defaultApplication()
// Do not remove root path here, it must be done after merging configs
.withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader()));
private final Map values = new HashMap<>();
private final Supplier fallbackSupplier;
private final String rootPath;
private String currentProfileName = DriverExecutionProfile.DEFAULT_NAME;
/**
* Creates an instance of {@link DefaultProgrammaticDriverConfigLoaderBuilder} with default
* settings.
*
* Fallback configuration for options that haven't been specified programmatically will be
* obtained from standard classpath resources. Application-specific classpath resources will be
* located using the {@linkplain Thread#getContextClassLoader() the current thread's context class
* loader}. This might not be suitable for OSGi deployments, which should use {@link
* #DefaultProgrammaticDriverConfigLoaderBuilder(ClassLoader)} instead.
*/
public DefaultProgrammaticDriverConfigLoaderBuilder() {
this(DEFAULT_FALLBACK_SUPPLIER, DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);
}
/**
* Creates an instance of {@link DefaultProgrammaticDriverConfigLoaderBuilder} with default
* settings but a custom class loader.
*
*
Fallback configuration for options that haven't been specified programmatically will be
* obtained from standard classpath resources. Application-specific classpath resources will be
* located using the provided {@link ClassLoader} instead of {@linkplain
* Thread#getContextClassLoader() the current thread's context class loader}.
*/
public DefaultProgrammaticDriverConfigLoaderBuilder(@NonNull ClassLoader appClassLoader) {
this(
() ->
ConfigFactory.defaultApplication(appClassLoader)
.withFallback(ConfigFactory.defaultReference(CqlSession.class.getClassLoader())),
DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);
}
/**
* Creates an instance of {@link DefaultProgrammaticDriverConfigLoaderBuilder} using a custom
* fallback config supplier.
*
* @param fallbackSupplier the supplier that will provide fallback configuration for options that
* haven't been specified programmatically.
* @param rootPath the root path used in non-programmatic sources (fallback reference.conf and
* system properties). In most cases it should be {@link
* DefaultDriverConfigLoader#DEFAULT_ROOT_PATH}. Cannot be null but can be empty.
*/
public DefaultProgrammaticDriverConfigLoaderBuilder(
@NonNull Supplier fallbackSupplier, @NonNull String rootPath) {
this.fallbackSupplier = fallbackSupplier;
this.rootPath = rootPath;
}
private ProgrammaticDriverConfigLoaderBuilder with(
@NonNull DriverOption option, @Nullable Object value) {
return with(option.getPath(), value);
}
private ProgrammaticDriverConfigLoaderBuilder with(@NonNull String path, @Nullable Object value) {
if (!DriverExecutionProfile.DEFAULT_NAME.equals(currentProfileName)) {
path = "profiles." + currentProfileName + "." + path;
}
if (!rootPath.isEmpty()) {
path = rootPath + "." + path;
}
values.put(path, value);
return this;
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder startProfile(@NonNull String profileName) {
currentProfileName = Objects.requireNonNull(profileName);
return this;
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder endProfile() {
currentProfileName = DriverExecutionProfile.DEFAULT_NAME;
return this;
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withBoolean(
@NonNull DriverOption option, boolean value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withBooleanList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withInt(@NonNull DriverOption option, int value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withIntList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withLong(@NonNull DriverOption option, long value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withLongList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withDouble(
@NonNull DriverOption option, double value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withDoubleList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withString(
@NonNull DriverOption option, @NonNull String value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withStringList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withStringMap(
@NonNull DriverOption option, @NonNull Map value) {
for (String key : value.keySet()) {
this.with(option.getPath() + "." + key, value.get(key));
}
return this;
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withBytes(@NonNull DriverOption option, long value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withBytesList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withDuration(
@NonNull DriverOption option, @NonNull Duration value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder withDurationList(
@NonNull DriverOption option, @NonNull List value) {
return with(option, value);
}
@NonNull
@Override
public ProgrammaticDriverConfigLoaderBuilder without(@NonNull DriverOption option) {
return with(option, null);
}
@NonNull
@Override
public DriverConfigLoader build() {
return new DefaultDriverConfigLoader(
() -> {
ConfigFactory.invalidateCaches();
Config programmaticConfig = buildConfig();
Config config =
ConfigFactory.defaultOverrides()
.withFallback(programmaticConfig)
.withFallback(fallbackSupplier.get())
.resolve();
// Only remove rootPath after the merge between system properties
// and fallback configuration, since both are supposed to
// contain the same rootPath prefix.
return rootPath.isEmpty() ? config : config.getConfig(rootPath);
});
}
private Config buildConfig() {
Config config = ConfigFactory.empty();
for (Map.Entry entry : values.entrySet()) {
config = config.withValue(entry.getKey(), ConfigValueFactory.fromAnyRef(entry.getValue()));
}
return config;
}
}