From c692412194734f4317f3fc6dac64eb40bad8ca97 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 13 Dec 2022 13:24:29 +0000 Subject: [PATCH] Reduce Config startup footprint --- .../RunTimeConfigurationGenerator.java | 26 ++-- .../steps/ConfigGenerationBuildStep.java | 147 ++++++++++++++---- .../runtime/configuration/ConfigRecorder.java | 61 +++----- .../runtime/configuration/ConfigUtils.java | 86 +++------- .../configuration/DefaultsConfigSource.java | 42 +++++ .../DisableableConfigSource.java | 74 +++++++++ 6 files changed, 283 insertions(+), 153 deletions(-) create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/DefaultsConfigSource.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/configuration/DisableableConfigSource.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java index 5f26e1176ce3e7..1c7122b1d8aa3a 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java @@ -405,12 +405,11 @@ public static final class GenerateOperation implements AutoCloseable { } // additional config builders - ResultHandle staticConfigBuilderInstances = clinit.newInstance(AL_NEW); + ResultHandle configBuilders = clinit.newInstance(AL_NEW); for (String configBuilder : staticConfigBuilders) { - ResultHandle staticConfigBuilderInstance = clinit.newInstance(MethodDescriptor.ofConstructor(configBuilder)); - clinit.invokeVirtualMethod(AL_ADD, staticConfigBuilderInstances, staticConfigBuilderInstance); + clinit.invokeVirtualMethod(AL_ADD, configBuilders, clinit.load(configBuilder)); } - clinit.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, buildTimeBuilder, staticConfigBuilderInstances); + clinit.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, buildTimeBuilder, configBuilders); clinitConfig = clinit.checkCast(clinit.invokeVirtualMethod(SRCB_BUILD, buildTimeBuilder), SmallRyeConfig.class); @@ -561,15 +560,12 @@ public void run() { } // add bootstrap config builders - ResultHandle bootstrapConfigBuilderInstances = readBootstrapConfig.newInstance(AL_NEW); + ResultHandle bootstrapConfigBuilders = readBootstrapConfig.newInstance(AL_NEW); for (String configBuilder : staticConfigBuilders) { - ResultHandle staticConfigBuilderInstance = readBootstrapConfig - .newInstance(MethodDescriptor.ofConstructor(configBuilder)); - readBootstrapConfig.invokeVirtualMethod(AL_ADD, bootstrapConfigBuilderInstances, - staticConfigBuilderInstance); + readBootstrapConfig.invokeVirtualMethod(AL_ADD, bootstrapConfigBuilders, + readBootstrapConfig.load(configBuilder)); } - readBootstrapConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, bootstrapBuilder, - bootstrapConfigBuilderInstances); + readBootstrapConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, bootstrapBuilder, bootstrapConfigBuilders); } // add in our custom sources @@ -657,13 +653,11 @@ public void run() { } // additional config builders - ResultHandle runtimeConfigBuilderInstances = readConfig.newInstance(AL_NEW); + ResultHandle configBuilders = readConfig.newInstance(AL_NEW); for (String configBuilder : runtimeConfigBuilders) { - ResultHandle runtimeConfigBuilderInstance = readConfig - .newInstance(MethodDescriptor.ofConstructor(configBuilder)); - readConfig.invokeVirtualMethod(AL_ADD, runtimeConfigBuilderInstances, runtimeConfigBuilderInstance); + readConfig.invokeVirtualMethod(AL_ADD, configBuilders, readConfig.load(configBuilder)); } - readConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, runTimeBuilder, runtimeConfigBuilderInstances); + readConfig.invokeStaticMethod(CU_CONFIG_BUILDER_LIST, runTimeBuilder, configBuilders); ResultHandle bootstrapConfig = null; if (bootstrapConfigSetupNeeded()) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java index 5e4788ee19edad..e4c3f93d345176 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java @@ -3,13 +3,11 @@ import static io.quarkus.deployment.configuration.ConfigMappingUtils.processExtensionConfigMapping; import static io.quarkus.deployment.steps.ConfigBuildSteps.SERVICES_PREFIX; import static io.quarkus.deployment.util.ServiceUtil.classNamesNamedIn; -import static io.quarkus.runtime.configuration.ConfigUtils.QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES; import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix; import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_LOCATIONS; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; import java.net.URI; @@ -23,7 +21,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; @@ -33,6 +30,7 @@ import org.eclipse.microprofile.config.ConfigValue; import org.eclipse.microprofile.config.spi.ConfigSource; import org.eclipse.microprofile.config.spi.ConfigSourceProvider; +import org.objectweb.asm.Opcodes; import io.quarkus.deployment.GeneratedClassGizmoAdaptor; import io.quarkus.deployment.IsNormal; @@ -47,7 +45,6 @@ import io.quarkus.deployment.builditem.ConfigurationBuildItem; import io.quarkus.deployment.builditem.ConfigurationTypeBuildItem; import io.quarkus.deployment.builditem.GeneratedClassBuildItem; -import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LiveReloadBuildItem; @@ -57,7 +54,6 @@ import io.quarkus.deployment.builditem.StaticInitConfigSourceFactoryBuildItem; import io.quarkus.deployment.builditem.StaticInitConfigSourceProviderBuildItem; import io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.configuration.BuildTimeConfigurationReader; import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator; @@ -65,19 +61,32 @@ import io.quarkus.deployment.recording.RecorderContext; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.ClassOutput; +import io.quarkus.gizmo.FieldDescriptor; +import io.quarkus.gizmo.MethodCreator; +import io.quarkus.gizmo.MethodDescriptor; +import io.quarkus.gizmo.ResultHandle; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.annotations.StaticInitSafe; +import io.quarkus.runtime.configuration.ConfigBuilder; import io.quarkus.runtime.configuration.ConfigDiagnostic; import io.quarkus.runtime.configuration.ConfigRecorder; -import io.quarkus.runtime.configuration.ConfigUtils; +import io.quarkus.runtime.configuration.DefaultsConfigSource; +import io.quarkus.runtime.configuration.DisableableConfigSource; import io.quarkus.runtime.configuration.QuarkusConfigValue; import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource; import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix; import io.smallrye.config.ConfigSourceFactory; import io.smallrye.config.PropertiesLocationConfigSourceFactory; import io.smallrye.config.SmallRyeConfig; +import io.smallrye.config.SmallRyeConfigBuilder; public class ConfigGenerationBuildStep { + private static final MethodDescriptor CONFIG_BUILDER = MethodDescriptor.ofMethod( + ConfigBuilder.class, "configBuilder", + SmallRyeConfigBuilder.class, SmallRyeConfigBuilder.class); + private static final MethodDescriptor WITH_SOURCES = MethodDescriptor.ofMethod( + SmallRyeConfigBuilder.class, "withSources", + SmallRyeConfigBuilder.class, ConfigSource[].class); @BuildStep void staticInitSources( @@ -91,43 +100,85 @@ void staticInitSources( @BuildStep void buildTimeRunTimeConfig( ConfigurationBuildItem configItem, - BuildProducer generatedResource, - BuildProducer nativeImageResource) throws Exception { + BuildProducer generatedClass, + BuildProducer reflectiveClass, + BuildProducer staticInitConfigBuilder, + BuildProducer runTimeConfigBuilder) { + + String className = "io.quarkus.runtime.generated.BuildTimeRunTimeFixedConfigSource"; + generateDefaultsConfigSource(generatedClass, reflectiveClass, configItem.getReadResult().getBuildTimeRunTimeValues(), + className, "BuildTime RunTime Fixed", Integer.MAX_VALUE); + + String builderClassName = className + "Builder"; + try (ClassCreator classCreator = ClassCreator.builder() + .classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true)) + .className(builderClassName) + .interfaces(ConfigBuilder.class) + .setFinal(true) + .build()) { + + MethodCreator method = classCreator.getMethodCreator(CONFIG_BUILDER); + ResultHandle configBuilder = method.getMethodParam(0); + + ResultHandle buildTimeRunTimeConfigSource = method.newInstance(MethodDescriptor.ofConstructor(className)); + ResultHandle disableableConfigSource = method.newInstance( + MethodDescriptor.ofConstructor(DisableableConfigSource.class, ConfigSource.class), + buildTimeRunTimeConfigSource); - Map buildTimeRunTimeValues = configItem.getReadResult().getBuildTimeRunTimeValues(); - Properties properties = new Properties(); - for (Map.Entry entry : buildTimeRunTimeValues.entrySet()) { - properties.setProperty(entry.getKey(), entry.getValue()); + ResultHandle configSources = method.newArray(ConfigSource.class, 1); + method.writeArrayValue(configSources, 0, disableableConfigSource); + + method.invokeVirtualMethod(WITH_SOURCES, configBuilder, configSources); + + method.returnValue(configBuilder); } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - properties.store(out, null); - generatedResource.produce(new GeneratedResourceBuildItem(QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES, out.toByteArray())); - nativeImageResource.produce(new NativeImageResourceBuildItem(QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES)); + reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, builderClassName)); + staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(builderClassName)); + runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(builderClassName)); } @BuildStep void runtimeDefaultsConfig( ConfigurationBuildItem configItem, List runTimeDefaults, - BuildProducer generatedResource, - BuildProducer nativeImageResource) throws IOException { + BuildProducer generatedClass, + BuildProducer reflectiveClass, + BuildProducer staticInitConfigBuilder, + BuildProducer runTimeConfigBuilder) { - Properties properties = new Properties(); + Map defaults = new HashMap<>(); for (RunTimeConfigurationDefaultBuildItem e : runTimeDefaults) { - properties.setProperty(e.getKey(), e.getValue()); + defaults.put(e.getKey(), e.getValue()); } + defaults.putAll(configItem.getReadResult().getRunTimeDefaultValues()); + + String className = "io.quarkus.runtime.generated.RunTimeDefaultsConfigSource"; + generateDefaultsConfigSource(generatedClass, reflectiveClass, defaults, + className, "RunTime Defaults", Integer.MIN_VALUE + 100); - Map runTimeDefaultValues = configItem.getReadResult().getRunTimeDefaultValues(); - for (Map.Entry entry : runTimeDefaultValues.entrySet()) { - properties.setProperty(entry.getKey(), entry.getValue()); + String builderClassName = className + "Builder"; + try (ClassCreator classCreator = ClassCreator.builder() + .classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true)) + .className(builderClassName) + .interfaces(ConfigBuilder.class) + .setFinal(true) + .build()) { + + MethodCreator method = classCreator.getMethodCreator(CONFIG_BUILDER); + ResultHandle configBuilder = method.getMethodParam(0); + + ResultHandle configSources = method.newArray(ConfigSource.class, 1); + method.writeArrayValue(configSources, 0, method.newInstance(MethodDescriptor.ofConstructor(className))); + + method.invokeVirtualMethod(WITH_SOURCES, configBuilder, configSources); + + method.returnValue(configBuilder); } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - properties.store(out, null); - generatedResource.produce( - new GeneratedResourceBuildItem(ConfigUtils.QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES, out.toByteArray())); - nativeImageResource.produce(new NativeImageResourceBuildItem(ConfigUtils.QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES)); + reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, builderClassName)); + staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(builderClassName)); + runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(builderClassName)); } @BuildStep @@ -359,6 +410,46 @@ private String appendProfileToFilename(String path, String activeProfile) { return String.format("%s-%s.%s", pathWithoutExtension, activeProfile, FilenameUtils.getExtension(path)); } + private static void generateDefaultsConfigSource( + BuildProducer generatedClass, + BuildProducer reflectiveClass, + Map defaults, + String className, + String sourceName, + int sourceOrdinal) { + + try (ClassCreator classCreator = ClassCreator.builder() + .classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true)) + .className(className) + .superClass(DefaultsConfigSource.class) + .setFinal(true) + .build()) { + + FieldDescriptor properties = FieldDescriptor.of(classCreator.getClassName(), "properties", Map.class); + classCreator.getFieldCreator(properties).setModifiers(Opcodes.ACC_STATIC | Opcodes.ACC_FINAL); + + MethodCreator clinit = classCreator.getMethodCreator("", void.class); + clinit.setModifiers(Opcodes.ACC_STATIC); + clinit.writeStaticField(properties, clinit.newInstance(MethodDescriptor.ofConstructor(HashMap.class))); + + ResultHandle map = clinit.readStaticField(properties); + MethodDescriptor put = MethodDescriptor.ofMethod(Map.class, "put", Object.class, Object.class, Object.class); + for (Map.Entry entry : defaults.entrySet()) { + clinit.invokeInterfaceMethod(put, map, clinit.load(entry.getKey()), clinit.load(entry.getValue())); + } + clinit.returnVoid(); + + MethodCreator ctor = classCreator.getMethodCreator("", void.class); + MethodDescriptor superCtor = MethodDescriptor.ofConstructor(DefaultsConfigSource.class, Map.class, String.class, + int.class); + ctor.invokeSpecialMethod(superCtor, ctor.getThis(), ctor.readStaticField(properties), + ctor.load(sourceName), ctor.load(sourceOrdinal)); + ctor.returnVoid(); + } + + reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, className)); + } + private static Set discoverService( Class serviceClass, BuildProducer reflectiveClass) throws IOException { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java index d338e053705911..2e42d598f7e955 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigRecorder.java @@ -1,11 +1,10 @@ package io.quarkus.runtime.configuration; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; -import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.ConfigValue; import org.eclipse.microprofile.config.spi.ConfigSource; @@ -13,10 +12,7 @@ import io.quarkus.runtime.annotations.Recorder; import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig.BuildTimeMismatchAtRuntime; -import io.smallrye.config.ConfigSourceInterceptorContext; -import io.smallrye.config.ExpressionConfigSourceInterceptor; import io.smallrye.config.SmallRyeConfig; -import io.smallrye.config.SmallRyeConfigBuilder; @Recorder public class ConfigRecorder { @@ -30,46 +26,16 @@ public ConfigRecorder(ConfigurationRuntimeConfig configurationConfig) { } public void handleConfigChange(Map buildTimeRuntimeValues) { - // Create a new Config without the "BuildTime RunTime Fixed" sources to check for different values - SmallRyeConfigBuilder configBuilder = ConfigUtils.emptyConfigBuilder(); - // We need to disable the expression resolution, because we may be missing expressions from the "BuildTime RunTime Fixed" source - configBuilder.withDefaultValue(Config.PROPERTY_EXPRESSIONS_ENABLED, "false"); - for (ConfigSource configSource : ConfigProvider.getConfig().getConfigSources()) { - if ("BuildTime RunTime Fixed".equals(configSource.getName())) { - continue; + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + // Disable the BuildTime RunTime Fixed (has the highest ordinal), because a lookup will get the expected value, + // and we have no idea if the user tried to override it in another source. + Optional builtTimeRunTimeFixedConfigSource = config.getConfigSource("BuildTime RunTime Fixed"); + if (builtTimeRunTimeFixedConfigSource.isPresent()) { + ConfigSource configSource = builtTimeRunTimeFixedConfigSource.get(); + if (configSource instanceof DisableableConfigSource) { + ((DisableableConfigSource) configSource).disable(); } - configBuilder.withSources(configSource); } - // Add a new expression resolution to fall back to the current Config if we cannot expand the expression - configBuilder.withInterceptors(new ExpressionConfigSourceInterceptor() { - @Override - public io.smallrye.config.ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { - return super.getValue(new ConfigSourceInterceptorContext() { - @Override - public io.smallrye.config.ConfigValue proceed(final String name) { - io.smallrye.config.ConfigValue configValue = context.proceed(name); - if (configValue == null) { - configValue = (io.smallrye.config.ConfigValue) ConfigProvider.getConfig().getConfigValue(name); - if (configValue.getValue() == null) { - return null; - } - } - return configValue; - } - - @Override - public Iterator iterateNames() { - return context.iterateNames(); - } - - @Override - public Iterator iterateValues() { - return context.iterateValues(); - } - }, name); - } - }); - SmallRyeConfig config = configBuilder.build(); List mismatches = new ArrayList<>(); for (Map.Entry entry : buildTimeRuntimeValues.entrySet()) { @@ -84,6 +50,15 @@ public Iterator iterateValues() { + " after building the application?"); } } + + // Enable the BuildTime RunTime Fixed. It should be fine doing these operations, because this is on startup + if (builtTimeRunTimeFixedConfigSource.isPresent()) { + ConfigSource configSource = builtTimeRunTimeFixedConfigSource.get(); + if (configSource instanceof DisableableConfigSource) { + ((DisableableConfigSource) configSource).enable(); + } + } + if (!mismatches.isEmpty()) { final String msg = "Build time property cannot be changed at runtime:\n" + String.join("\n", mismatches); switch (configurationConfig.buildTimeMismatchAtRuntime) { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java index 42227069a18166..c08d30c8533fa8 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java @@ -5,10 +5,9 @@ import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE; import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT; import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES; -import static java.lang.Integer.MAX_VALUE; -import static java.lang.Integer.MIN_VALUE; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -39,14 +38,12 @@ import io.smallrye.config.DotEnvConfigSourceProvider; import io.smallrye.config.EnvConfigSource; import io.smallrye.config.FallbackConfigSourceInterceptor; -import io.smallrye.config.KeyMap; import io.smallrye.config.NameIterator; import io.smallrye.config.Priorities; import io.smallrye.config.RelocateConfigSourceInterceptor; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SysPropConfigSource; -import io.smallrye.config.common.MapBackedConfigSource; import io.smallrye.config.common.utils.ConfigSourceUtil; /** @@ -58,8 +55,6 @@ public final class ConfigUtils { * The name of the property associated with a random UUID generated at launch time. */ static final String UUID_KEY = "quarkus.uuid"; - public static final String QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES = "quarkus-build-time-runtime.properties"; - public static final String QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES = "quarkus-runtime-config-defaults.properties"; private ConfigUtils() { } @@ -116,8 +111,6 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b builder.addDiscoveredValidator(); builder.withDefaultValue(UUID_KEY, UUID.randomUUID().toString()); builder.withSources(new DotEnvConfigSourceProvider()); - builder.withSources(new DefaultsConfigSource(loadBuildTimeRunTimeValues(), "BuildTime RunTime Fixed", MAX_VALUE)); - builder.withSources(new DefaultsConfigSource(loadRunTimeDefaultValues(), "RunTime Defaults", MIN_VALUE + 100)); } else { List sources = new ArrayList<>(); sources.addAll(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)); @@ -213,16 +206,28 @@ public OptionalInt getPriority() { } @SuppressWarnings("unchecked") - public static SmallRyeConfigBuilder configBuilder(SmallRyeConfigBuilder builder, List configBuilders) { - configBuilders.sort(ConfigBuilderComparator.INSTANCE); + public static SmallRyeConfigBuilder configBuilder(SmallRyeConfigBuilder builder, List configBuildersNames) { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + List configBuilders = new ArrayList<>(); + for (String configBuilderName : configBuildersNames) { + Class configBuilderClass = (Class) contextClassLoader + .loadClass(configBuilderName); + configBuilders.add(configBuilderClass.getDeclaredConstructor().newInstance()); + } + configBuilders.sort(ConfigBuilderComparator.INSTANCE); - for (ConfigBuilder configBuilder : configBuilders) { - builder = configBuilder.configBuilder(builder); - if (builder == null) { - throw new ConfigurationException(configBuilder.getClass().getName() + " returned a null builder"); + for (ConfigBuilder configBuilder : configBuilders) { + builder = configBuilder.configBuilder(builder); + if (builder == null) { + throw new ConfigurationException(configBuilder.getClass().getName() + " returned a null builder"); + } } - } + } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | NoSuchMethodException + | IllegalAccessException e) { + throw new ConfigurationException(e); + } return builder; } @@ -255,25 +260,6 @@ public static void addSourceFactoryProvider(SmallRyeConfigBuilder builder, Confi builder.withSources(provider.getConfigSourceFactory(Thread.currentThread().getContextClassLoader())); } - public static Map loadBuildTimeRunTimeValues() { - try { - URL resource = Thread.currentThread().getContextClassLoader().getResource(QUARKUS_BUILD_TIME_RUNTIME_PROPERTIES); - return resource != null ? ConfigSourceUtil.urlToMap(resource) : Collections.emptyMap(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static Map loadRunTimeDefaultValues() { - try { - URL resource = Thread.currentThread().getContextClassLoader() - .getResource(QUARKUS_RUNTIME_CONFIG_DEFAULTS_PROPERTIES); - return resource != null ? ConfigSourceUtil.urlToMap(resource) : Collections.emptyMap(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - public static void addMapping(SmallRyeConfigBuilder builder, String mappingClass, String prefix) { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); try { @@ -414,38 +400,6 @@ public Set getPropertyNames() { } } - static class DefaultsConfigSource extends MapBackedConfigSource { - private final KeyMap wildcards; - - public DefaultsConfigSource(final Map properties, final String name, final int ordinal) { - // Defaults may contain wildcards, but we don't want to expose them in getPropertyNames, so we need to filter them - super(name, filterWildcards(properties), ordinal); - this.wildcards = new KeyMap<>(); - for (Map.Entry entry : properties.entrySet()) { - if (entry.getKey().contains("*")) { - this.wildcards.findOrAdd(entry.getKey()).putRootValue(entry.getValue()); - } - } - } - - @Override - public String getValue(final String propertyName) { - String value = super.getValue(propertyName); - return value == null ? wildcards.findRootValue(propertyName) : value; - } - - private static Map filterWildcards(final Map properties) { - Map filtered = new HashMap<>(); - for (Map.Entry entry : properties.entrySet()) { - if (entry.getKey().contains("*")) { - continue; - } - filtered.put(entry.getKey(), entry.getValue()); - } - return filtered; - } - } - private static class ConfigBuilderComparator implements Comparator { private static final ConfigBuilderComparator INSTANCE = new ConfigBuilderComparator(); diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/DefaultsConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/DefaultsConfigSource.java new file mode 100644 index 00000000000000..1445e25bf3ad37 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/DefaultsConfigSource.java @@ -0,0 +1,42 @@ +package io.quarkus.runtime.configuration; + +import java.util.HashMap; +import java.util.Map; + +import io.quarkus.runtime.annotations.StaticInitSafe; +import io.smallrye.config.KeyMap; +import io.smallrye.config.common.MapBackedConfigSource; + +@StaticInitSafe +public class DefaultsConfigSource extends MapBackedConfigSource { + private final KeyMap wildcards; + + public DefaultsConfigSource(final Map properties, final String name, final int ordinal) { + // Defaults may contain wildcards, but we don't want to expose them in getPropertyNames, so we need to filter + // them + super(name, filterWildcards(properties), ordinal); + this.wildcards = new KeyMap<>(); + for (Map.Entry entry : properties.entrySet()) { + if (entry.getKey().contains("*")) { + this.wildcards.findOrAdd(entry.getKey()).putRootValue(entry.getValue()); + } + } + } + + @Override + public String getValue(final String propertyName) { + String value = super.getValue(propertyName); + return value == null ? wildcards.findRootValue(propertyName) : value; + } + + private static Map filterWildcards(final Map properties) { + Map filtered = new HashMap<>(); + for (Map.Entry entry : properties.entrySet()) { + if (entry.getKey().contains("*")) { + continue; + } + filtered.put(entry.getKey(), entry.getValue()); + } + return filtered; + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/DisableableConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/DisableableConfigSource.java new file mode 100644 index 00000000000000..5c4e96a16f64e9 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/DisableableConfigSource.java @@ -0,0 +1,74 @@ +package io.quarkus.runtime.configuration; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.microprofile.config.spi.ConfigSource; + +public class DisableableConfigSource implements ConfigSource { + private final ConfigSource source; + private final ConfigSource emptySource; + + private AtomicReference activeSource; + + public DisableableConfigSource(final ConfigSource source) { + this.source = source; + this.emptySource = new ConfigSource() { + @Override + public Set getPropertyNames() { + return Collections.emptySet(); + } + + @Override + public String getValue(final String propertyName) { + return null; + } + + @Override + public String getName() { + return source.getName(); + } + + @Override + public int getOrdinal() { + return source.getOrdinal(); + } + }; + activeSource = new AtomicReference<>(source); + } + + @Override + public Map getProperties() { + return activeSource.get().getProperties(); + } + + @Override + public Set getPropertyNames() { + return activeSource.get().getPropertyNames(); + } + + @Override + public int getOrdinal() { + return source.getOrdinal(); + } + + @Override + public String getValue(final String propertyName) { + return activeSource.get().getValue(propertyName); + } + + @Override + public String getName() { + return source.getName(); + } + + public void enable() { + activeSource.compareAndSet(emptySource, source); + } + + public void disable() { + activeSource.compareAndSet(source, emptySource); + } +}