Skip to content

Commit

Permalink
Consistently consider quoted AND non-quoted versions of quarkus.datas…
Browse files Browse the repository at this point in the history
…ource configuration properties

We were already taking both versions into account in
DevServicesDatasourceConfigurationHandlerBuildItem, but not in every
other place.
  • Loading branch information
yrodiere committed Jul 20, 2022
1 parent e2e33be commit 52925f7
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.quarkus.deployment.builditem;

import java.util.Collection;
import java.util.List;

import io.quarkus.builder.item.MultiBuildItem;

/**
Expand All @@ -12,21 +15,40 @@
*/
public final class DevServicesAdditionalConfigBuildItem extends MultiBuildItem {

private final String triggeringKey;
private final Collection<String> triggeringKeys;
private final String key;
private final String value;
private final Runnable callbackWhenEnabled;

/**
* @deprecated Call
* {@link DevServicesAdditionalConfigBuildItem#DevServicesAdditionalConfigBuildItem(Collection, String, String, Runnable)}
* instead.
*/
@Deprecated
public DevServicesAdditionalConfigBuildItem(String triggeringKey,
String key, String value, Runnable callbackWhenEnabled) {
this.triggeringKey = triggeringKey;
this(List.of(triggeringKey), key, value, callbackWhenEnabled);
}

public DevServicesAdditionalConfigBuildItem(Collection<String> triggeringKeys,
String key, String value, Runnable callbackWhenEnabled) {
this.triggeringKeys = triggeringKeys;
this.key = key;
this.value = value;
this.callbackWhenEnabled = callbackWhenEnabled;
}

/**
* @deprecated Call {@link #getTriggeringKeys()} instead.
*/
@Deprecated
public String getTriggeringKey() {
return triggeringKey;
return getTriggeringKeys().iterator().next();
}

public Collection<String> getTriggeringKeys() {
return triggeringKeys;
}

public String getKey() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void run() {
// On contrary to dev services config, "additional" config build items are
// produced on each restart, so we don't want to remember them from one restart to the next.
for (DevServicesAdditionalConfigBuildItem item : devServicesAdditionalConfigBuildItems) {
if (newProperties.containsKey(item.getTriggeringKey())) {
if (item.getTriggeringKeys().stream().anyMatch(newProperties::containsKey)) {
var callback = item.getCallbackWhenEnabled();
if (callback != null) {
callback.run(); // This generally involves logging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Properties;
import java.util.Set;
Expand All @@ -25,6 +26,7 @@
import java.util.UUID;
import java.util.function.IntFunction;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
Expand Down Expand Up @@ -270,6 +272,48 @@ public static boolean isPropertyPresent(String propertyName) {
return ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).isPropertyPresent(propertyName);
}

/**
* Checks if any of the given properties is present in the current Configuration.
* <p>
* Because the sources may not expose the property directly in {@link ConfigSource#getPropertyNames()}, we cannot
* reliably determine if the property is present in the properties list. The property needs to be retrieved to make
* sure it exists. Also, if the value is an expression, we want to ignore expansion, because this is not relevant
* for the check and the expansion value may not be available at this point.
* <p>
* It may be interesting to expose such API in SmallRyeConfig directly.
*
* @param propertyNames The configuration property names
* @return true if the property is present or false otherwise.
*/
public static boolean isAnyPropertyPresent(Collection<String> propertyNames) {
for (String propertyName : propertyNames) {
if (isPropertyPresent(propertyName)) {
return true;
}
}
return false;
}

/**
* Get the value of the first given property present in the current Configuration,
* or {@link Optional#empty()} if none of the properties is present.
*
* @param <T> The property type
* @param propertyNames The configuration property names
* @param propertyType The type that the resolved property value should be converted to
* @return true if the property is present or false otherwise.
*/
public static <T> Optional<T> getFirstOptionalValue(List<String> propertyNames, Class<T> propertyType) {
Config config = ConfigProvider.getConfig();
for (String propertyName : propertyNames) {
Optional<T> value = config.getOptionalValue(propertyName, propertyType);
if (value.isPresent()) {
return value;
}
}
return Optional.empty();
}

/**
* We override the EnvConfigSource, because we don't want the nothing back from getPropertiesNames at build time.
* The mapping is one way and there is no way to map them back.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.datasource.common.runtime;

import java.util.Collection;
import java.util.List;

public final class DataSourceUtil {

Expand All @@ -14,6 +15,17 @@ public static boolean hasDefault(Collection<String> dataSourceNames) {
return dataSourceNames.contains(DEFAULT_DATASOURCE_NAME);
}

public static List<String> dataSourcePropertyKeys(String datasourceName, String radical) {
if (datasourceName == null || DataSourceUtil.isDefault(datasourceName)) {
return List.of("quarkus.datasource." + radical);
} else {
// Two possible syntaxes: with or without quotes
return List.of(
"quarkus.datasource.\"" + datasourceName + "\"." + radical,
"quarkus.datasource." + datasourceName + "." + radical);
}
}

private DataSourceUtil() {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package io.quarkus.datasource.deployment.spi;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
import io.quarkus.runtime.configuration.ConfigUtils;

/**
Expand Down Expand Up @@ -56,33 +59,24 @@ public static DevServicesDatasourceConfigurationHandlerBuildItem jdbc(String dbK
public Map<String, String> apply(String dsName,
DevServicesDatasourceProvider.RunningDevServicesDatasource runningDevDb) {
String jdbcUrl = runningDevDb.getJdbcUrl();
if (dsName == null) {
return Collections.singletonMap("quarkus.datasource.jdbc.url", jdbcUrl);
} else {
// we use quoted and unquoted versions because depending on whether a user configured other JDBC properties
// one of the URLs may be ignored
// see https://github.com/quarkusio/quarkus/issues/21387
return Map.of(
datasourceURLPropName(dsName), jdbcUrl,
datasourceURLPropName("\"" + dsName + "\""), jdbcUrl);
}
// we use datasourceURLPropNames to generate quoted and unquoted versions of the property key,
// because depending on whether a user configured other JDBC properties
// one of the URLs may be ignored
// see https://github.com/quarkusio/quarkus/issues/21387
return datasourceURLPropNames(dsName).stream()
.collect(Collectors.toMap(Function.identity(), ignored -> jdbcUrl));
}

}, new Predicate<String>() {
@Override
public boolean test(String dsName) {
if (dsName == null) {
return ConfigUtils.isPropertyPresent("quarkus.datasource.jdbc.url");
} else {
return ConfigUtils.isPropertyPresent(datasourceURLPropName(dsName)) ||
ConfigUtils.isPropertyPresent(datasourceURLPropName("\"" + dsName + "\""));
}
return ConfigUtils.isAnyPropertyPresent(datasourceURLPropNames(dsName));
}
});
}

private static String datasourceURLPropName(String dsName) {
return String.format("quarkus.datasource.%s.jdbc.url", dsName);
private static List<String> datasourceURLPropNames(String dsName) {
return DataSourceUtil.dataSourcePropertyKeys(dsName, "jdbc.url");
}

public static DevServicesDatasourceConfigurationHandlerBuildItem reactive(String dbKind) {
Expand All @@ -92,41 +86,22 @@ public static DevServicesDatasourceConfigurationHandlerBuildItem reactive(String
public Map<String, String> apply(String dsName,
DevServicesDatasourceProvider.RunningDevServicesDatasource runningDevDb) {
String reactiveUrl = runningDevDb.getReactiveUrl();
if (dsName == null) {
return Collections.singletonMap("quarkus.datasource.reactive.url", reactiveUrl);
} else {
// we use quoted and unquoted versions because depending on whether a user configured other JDBC properties
// one of the URLs may be ignored
// see https://github.com/quarkusio/quarkus/issues/21387
return Map.of(
datasourceReactiveURLPropName(dsName, false), reactiveUrl,
datasourceReactiveURLPropName(dsName, true), reactiveUrl);
}
// we use datasourceURLPropNames to generate quoted and unquoted versions of the property key,
// because depending on whether a user configured other reactive properties
// one of the URLs may be ignored
// see https://github.com/quarkusio/quarkus/issues/21387
return datasourceReactiveURLPropNames(dsName).stream()
.collect(Collectors.toMap(Function.identity(), ignored -> reactiveUrl));
}
}, new Predicate<String>() {
@Override
public boolean test(String dsName) {
if (dsName == null) {
return ConfigUtils.isPropertyPresent("quarkus.datasource.reactive.url");
} else {
return ConfigUtils.isPropertyPresent(datasourceReactiveURLPropName(dsName, false)) ||
ConfigUtils.isPropertyPresent(datasourceReactiveURLPropName(dsName, true));
}
return ConfigUtils.isAnyPropertyPresent(datasourceReactiveURLPropNames(dsName));
}
});
}

private static String datasourceReactiveURLPropName(String dsName, boolean quotedName) {
StringBuilder key = new StringBuilder("quarkus.datasource");
key.append('.');
if (quotedName) {
key.append('"');
}
key.append(dsName);
if (quotedName) {
key.append('"');
}
key.append(".reactive.url");
return key.toString();
private static List<String> datasourceReactiveURLPropNames(String dsName) {
return DataSourceUtil.dataSourcePropertyKeys(dsName, "reactive.url");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import io.quarkus.datasource.common.runtime.DataSourceUtil;
import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem;
import io.quarkus.datasource.deployment.spi.DevServicesDatasourceConfigurationHandlerBuildItem;
import io.quarkus.datasource.deployment.spi.DevServicesDatasourceContainerConfig;
Expand All @@ -35,6 +36,7 @@
import io.quarkus.deployment.logging.LoggingSetupBuildItem;
import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.configuration.ConfigUtils;

public class DevServicesDatasourceProcessor {

Expand Down Expand Up @@ -257,11 +259,6 @@ private RunningDevService startDevDb(String dbName,
consoleInstalledBuildItem,
loggingSetupBuildItem);
try {
String prefix = "quarkus.datasource.";
if (dbName != null) {
prefix = prefix + dbName + ".";
}

DevServicesDatasourceContainerConfig containerConfig = new DevServicesDatasourceContainerConfig(
dataSourceBuildTimeConfig.devservices.imageName,
dataSourceBuildTimeConfig.devservices.containerProperties,
Expand All @@ -273,26 +270,34 @@ private RunningDevService startDevDb(String dbName,
dataSourceBuildTimeConfig.devservices.password);

DevServicesDatasourceProvider.RunningDevServicesDatasource datasource = devDbProvider
.startDatabase(ConfigProvider.getConfig().getOptionalValue(prefix + "username", String.class),
ConfigProvider.getConfig().getOptionalValue(prefix + "password", String.class),
.startDatabase(
ConfigUtils.getFirstOptionalValue(DataSourceUtil.dataSourcePropertyKeys(dbName, "username"),
String.class),
ConfigUtils.getFirstOptionalValue(DataSourceUtil.dataSourcePropertyKeys(dbName, "password"),
String.class),
Optional.ofNullable(dbName), containerConfig,
launchMode, globalDevServicesConfig.timeout);

propertiesMap.put(prefix + "db-kind", dataSourceBuildTimeConfig.dbKind.orElse(null));
String devServicesPrefix = prefix + "devservices.";
for (String key : DataSourceUtil.dataSourcePropertyKeys(dbName, "db-kind")) {
propertiesMap.put(key, dataSourceBuildTimeConfig.dbKind.orElse(null));
}
String devServicesPrefix = "devservices.";
if (dataSourceBuildTimeConfig.devservices.command.isPresent()) {
propertiesMap.put(devServicesPrefix + "command", dataSourceBuildTimeConfig.devservices.command.get());
setDataSourceProperties(propertiesMap, dbName, devServicesPrefix + "command",
dataSourceBuildTimeConfig.devservices.command.get());
}
if (dataSourceBuildTimeConfig.devservices.imageName.isPresent()) {
propertiesMap.put(devServicesPrefix + "image-name", dataSourceBuildTimeConfig.devservices.imageName.get());
setDataSourceProperties(propertiesMap, dbName, devServicesPrefix + "image-name",
dataSourceBuildTimeConfig.devservices.imageName.get());
}
if (dataSourceBuildTimeConfig.devservices.port.isPresent()) {
propertiesMap.put(devServicesPrefix + "port",
setDataSourceProperties(propertiesMap, dbName, devServicesPrefix + "port",
Integer.toString(dataSourceBuildTimeConfig.devservices.port.getAsInt()));
}
if (!dataSourceBuildTimeConfig.devservices.properties.isEmpty()) {
for (var e : dataSourceBuildTimeConfig.devservices.properties.entrySet()) {
propertiesMap.put(devServicesPrefix + "properties." + e.getKey(), e.getValue());
setDataSourceProperties(propertiesMap, dbName, devServicesPrefix + "properties." + e.getKey(),
e.getValue());
}
}

Expand All @@ -301,21 +306,23 @@ private RunningDevService startDevDb(String dbName,
devDebProperties.putAll(devDbConfigurationHandlerBuildItem.getConfigProviderFunction()
.apply(dbName, datasource));
}
devDebProperties.put(prefix + "db-kind", defaultDbKind.get());
setDataSourceProperties(devDebProperties, dbName, "db-kind", defaultDbKind.get());
if (datasource.getUsername() != null) {
devDebProperties.put(prefix + "username", datasource.getUsername());
setDataSourceProperties(devDebProperties, dbName, "username", datasource.getUsername());
}
if (datasource.getPassword() != null) {
devDebProperties.put(prefix + "password", datasource.getPassword());
setDataSourceProperties(devDebProperties, dbName, "password", datasource.getPassword());
}
compressor.close();
log.info("Dev Services for " + prettyName
+ " (" + defaultDbKind.get() + ") started.");

String devservices = prefix + "devservices.";
List<String> devservicesPrefixes = DataSourceUtil.dataSourcePropertyKeys(dbName, "devservices.");
for (var name : ConfigProvider.getConfig().getPropertyNames()) {
if (name.startsWith(devservices)) {
devDebProperties.put(name, ConfigProvider.getConfig().getValue(name, String.class));
for (String prefix : devservicesPrefixes) {
if (name.startsWith(prefix)) {
devDebProperties.put(name, ConfigProvider.getConfig().getValue(name, String.class));
}
}
}
return new RunningDevService(defaultDbKind.get(), datasource.getId(), datasource.getCloseTask(), devDebProperties);
Expand All @@ -325,6 +332,13 @@ private RunningDevService startDevDb(String dbName,
}
}

private void setDataSourceProperties(Map<String, String> propertiesMap, String dbName, String propertyKeyRadical,
String value) {
for (String key : DataSourceUtil.dataSourcePropertyKeys(dbName, propertyKeyRadical)) {
propertiesMap.put(key, value);
}
}

private DevServicesDatasourceResultBuildItem.DbResult toDbResult(RunningDevService devService) {
if (devService == null) {
return null;
Expand Down
Loading

0 comments on commit 52925f7

Please sign in to comment.