From 328a3a959c6634e9e839a4c9266492df9915f74a Mon Sep 17 00:00:00 2001 From: David Kral Date: Tue, 17 Oct 2023 10:13:04 +0200 Subject: [PATCH 1/2] Helidon SE config Signed-off-by: David Kral --- docs/includes/attributes.adoc | 3 + docs/se/config/advanced-configuration.adoc | 174 +++++---------------- docs/se/config/config-profiles.adoc | 6 +- docs/se/config/property-mapping.adoc | 6 +- docs/se/config/supported-formats.adoc | 65 ++++---- docs/se/guides/config.adoc | 54 ++++--- 6 files changed, 108 insertions(+), 200 deletions(-) diff --git a/docs/includes/attributes.adoc b/docs/includes/attributes.adoc index 84f3eef175e..b6963e38eb4 100644 --- a/docs/includes/attributes.adoc +++ b/docs/includes/attributes.adoc @@ -190,6 +190,9 @@ endif::[] :http-javadoc-base-url: {javadoc-base-url}/io.helidon.http :common-javadoc-base-url: {javadoc-base-url}/io.helidon.common :config-javadoc-base-url: {javadoc-base-url}/io.helidon.config +:config-etcd-javadoc-base-url: {javadoc-base-url}/io.helidon.config.etcd +:config-git-javadoc-base-url: {javadoc-base-url}/io.helidon.config.git +:config-mapping-javadoc-base-url: {javadoc-base-url}/io.helidon.config.objectmapping :configurable-javadoc-base-url: {javadoc-base-url}/io.helidon.common.configurable :faulttolerance-javadoc-base-url: {javadoc-base-url}/io.helidon.faulttolerance :grpc-server-javadoc-base-url: {javadoc-base-url}/io.helidon.grpc.server diff --git a/docs/se/config/advanced-configuration.adoc b/docs/se/config/advanced-configuration.adoc index bb4ef445ef4..31b80d4236b 100644 --- a/docs/se/config/advanced-configuration.adoc +++ b/docs/se/config/advanced-configuration.adoc @@ -155,14 +155,13 @@ Config config = Config.create( [source,java] ---- Config config = Config.create( - ConfigSources.create("app.greeting = Hi", "text/x-java-properties")); // <2> + ConfigSources.create("app.greeting = Hi", MediaTypes.create("text/x-java-properties"))); ---- ==== `Map` [source,java] ---- Config config = Config.crate( ConfigSources.create(Map.of("app.page-size", "20")) - .lax() // <3> .build()); // <1> ---- ==== _ad hoc_ Config Nodes @@ -177,12 +176,9 @@ Config config = Config.create( .build())); ---- <1> `ConfigSources.create` variants for `Properties` or `Map` arguments return a - `ConfigSources.MapBuilder` instance. -<2> A similar `create` variant accepts a `Readable` instead of a `String`. -<3> `MapBuilder` by default throws an exception if a key appears more than once -in the map. The `lax()` method relaxes this; the config system logs a warning instead. + `MapConfigSource.Builder` instance. -=== Multi-Source ``Config``s and Composite Config Sources +=== Multi-Source Configs and Composite Config Sources Although the examples above use a single source, you can build a single `Config` from multiple sources. @@ -259,37 +255,28 @@ sources gives your application a way to access all config elements distinctly ev if their keys would otherwise conflict. ===== Merging Strategies -The `ConfigSources.create(Supplier...)` and `ConfigSources.create(List...)` -methods return a `CompositeBuilder`. -By default, earlier sources in the list have higher priority than later ones, meaning +When creating config from multiple sources it is possible, that the same key comes from multiple +sources. By default, earlier sources in the list have higher priority than later ones, meaning that if the same key appears in two or more sources the source earlier in the list prevails. -Each ``CompositeConfigSource``'s _merging strategy_ actually controls this behavior. The config system provides the `FallbackMergingStrategy` which implements the default, "first wins" algorithm. You can write your own -implementation of -link:{config-javadoc-base-url}/io/helidon/config/ConfigSources.MergingStrategy.html[`ConfigSources.MergingStrategy`] +implementation of MergingStrategy interface and use it instead to provide a different algorithm. [source,java] .Composite config source example ---- -Config config = Config.create( // <1> - ConfigSources.create(file("conf/dev.properties").optional(), // <2> - file("conf/config.properties").optional()) // <2> - .add(classpath("application.properties")) // <3> - .mergingStrategy(ConfigSources.MergingStrategy.fallback())); // <4> +Config config = Config.builder() + .addSource(file("config-file.properties")) + .addSource(classpath("application.yaml")) + .mergingStrategy(MergingStrategy.fallback()) // <1> + .build(); ---- -<1> Creates a new `Config` instance from a single composite config source. -<2> Method `ConfigSources.create(sources...)` returns `CompositeBuilder` instance - initialized with two sources (from `dev.properties` and `config.properties` - files). -<3> Adds third config source (`application.properties` on - classpath) to the same `CompositeBuilder`. -<4> Specifies the merging strategy. This example uses the default fallback +<1> Specifies the merging strategy. This example uses the default fallback merging strategy. == Advanced Config Parsers @@ -328,7 +315,7 @@ because there might be more than one inferred media type. .Specify `mediaType` for config source ---- Config config = Config.create(classpath("props") // <1> - .mediaType("text/x-java-properties")); // <2> + .mediaType(MediaTypes.create("text/x-java-properties"))); // <2> ---- <1> The config system cannot infer the media type because there is no file @@ -358,7 +345,7 @@ a `ConfigException` when trying to prepare the configuration. ===== By Application Directive Your application can specify which parser to use for a config source. The -`AbstractParsableConfigSource.Builder` class exposes the `parser` method, which +`AbstractConfigSourceBuilder` class exposes the `parser` method, which accepts the `ConfigParser` to be used for that source. Several methods on `ConfigSources` such as `classpath`, `directory`, and `file` return this builder class. @@ -416,15 +403,15 @@ Config config = Config.create( classpath("application.yaml") .mediaTypeMapping( // <1> key -> "app".equals(key.toString()) // <2> - ? "application/json" - : null)); + ? Optional.of(MediaTypes.APPLICATION_JSON) + : Optional.empty())); assert config.get("secrets.username").asString() // <3> .get().equals("jose"); assert config.get("secrets.password").asString() // <3> .get().equals("^ery$ecretP&ssword"); -assert config.get("app").type() == Type.OBJECT; // <4> +assert config.get("app").type() == Config.Type.OBJECT; // <4> assert config.get("app.greeting") // <3> .asString().get().equals("Hello"); @@ -458,7 +445,7 @@ you want to use for parsing those keys' values. .Specify JSON formatted property' parser instance ---- Config config = Config.create( - ConfigSources.classpath("application.yaml") + classpath("application.yaml") .parserMapping( // <1> key -> "app".equals(key.toString()) // <2> ? Optional.of(HoconConfigParser.create()) @@ -637,9 +624,8 @@ Each of these uses an executor to perform its work. The config system provides d executors, but your application can specify different ones if necessary. === Executors for Polling Strategy -The two methods `PollingStrategies.regular(Duration)` and -`PollingStrategies.watch(Path)` return builders for their respective strategies. -Both builders expose the `executor` method which your application can invoke, passing a +The method `PollingStrategies.regular(Duration)` return builder for polling strategy. +This builder provides `executor` method which your application can invoke, passing a `java.util.concurrent.ScheduledExecutorService` instance it requires for the polling work. By default, each polling strategy instance uses a separate thread pool executor. @@ -656,49 +642,45 @@ Config config = Config.create( .pollingStrategy( PollingStrategies.regular(Duration.ofSeconds(2)) // <2> .executor(executor)), // <3> - ConfigSources.create("conf/config.properties") + ConfigSources.file("conf/config.properties") .pollingStrategy( - path -> PollingStrategies.watch(path) // <4> - .executor(executor))); // <5> + PollingStrategies.regular(Duration.ofSeconds(5)) // <2> + .executor(executor))); // <4> ---- -<1> Prepares a thread pool executor with core pool size set `2` to be shared by - all polling strategies. +<1> Prepares a thread pool executor with core pool size set `2`. <2> Selects the built-in periodic polling strategy. <3> Tells the config system to use the specific executor to poll the `dev.properties` config source. -<4> Uses the Java filesystem `WatchService` to monitor the specified path. -<5> Tells the config system to use the same executor to monitor the path. +<4> Tells the config system to use the specific executor to poll the +`config.properties` config source. -=== Publishers for Source Change Events -Recall that when a polling strategy detects a change in a source, it informs +=== Executors for Source Change Events +Recall that when a change watcher detects a change in a source, it informs interested parties of the changes. By default, each `Config.Builder` arranges for the resulting `Config` tree to use a shared executor that reuses available threads from a pool, creating new threads as needed. The same executor is used for actually reloading the source. -Your application can invoke the polling strategy builder's `changesExecutor` method to -tell the builder -to use a different `Executor`. (As an aside, your application can also control -the size of the buffer used for holding source change events by invoking the -builder's `changesMaxBuffer` method. The default is 256.) +Your application can invoke the system watcher builder's `executor` method to +tell the builder to use a different `Executor`. [source,java] .Customize config and override sources' executors ---- -Executor executor = Executors.newCachedThreadPool(); // <1> +ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);// <1> Config config = Config.builder() .overrides( OverrideSources.file("conf/overrides.properties") - .pollingStrategy(PollingStrategies::watch) - .changesExecutor(executor) // <2> - .changesMaxBuffer(4)) // <3> + .changeWatcher(FileSystemWatcher.builder() + .executor(executor) // <2> + .build())) .sources( ConfigSources.file("conf/env.yaml") - .pollingStrategy(PollingStrategies::watch) - .changesExecutor(executor) // <4> - .changesMaxBuffer(4)) // <4> + .changeWatcher(FileSystemWatcher.builder() + .executor(executor) // <3> + .build())) .build(); ---- @@ -706,89 +688,9 @@ Config config = Config.builder() <2> Tells the builder that the resulting overrides source should use the specified `Executor` for notifying interested parties of changes and for reloading the override source. -<3> Specifies an event buffer size of 4. -<4> Uses the same `Executor` and event buffer size for the config source as for +<3> Uses the same `Executor` and event buffer size for the config source as for the override source above. -=== Composite Config Source Executor -When your application supplies multiple sources to a config builder, as with -`Config.create(Supplier...)` and `Config.create(List>)`, -the config system -automatically uses a _composite config source_ which aggregates the separate -sources but also listens for changes to any of the individual sources, so it can -delegate the change notification. For this change detection and notification the -config system, by default, uses an executor with a dedicated thread pool that is -shared across all `Config` instances. - -Your application can invoke the builder's `changesExecutor` method to use a -different `ScheduledExecutorService` instance. -The builder returned by the `from` methods mentioned above is a -link:{config-javadoc-base-url}/io/helidon/config/ConfigSources.CompositeBuilder.html[CompositeBuilder] -which extends `Config.Builder`. - -Because a composite source might yield more numerous change events -- because of the -multiple underlying sources -- your application can specify _debounce timeout_ -for the composite source by invoking the `CompositeBuilder.changesDebounce(Duration)` -method. The composite source aggregates multiple change events within this _debounce timeout_ -period into a single event and broadcasts that one instead. Next, it reloads the sources at -that time, not necessarily in response to every single change in any source. -The default is `100` milliseconds. - -[source,java] -.Customize composite source executors ----- -ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); // <1> - -Config config = Config.create( - ConfigSources.create(file("conf/dev.properties") // <2> - .pollingStrategy(PollingStrategies::watch), - file("conf/config.properties") // <2> - .pollingStrategy(PollingStrategies::watch)) - .changesExecutor(executor) // <3> - .changesMaxBuffer(4) // <4> - .changesDebounce(Duration.ofSeconds(1))); // <5> ----- - -<1> Prepares a thread pool executor. -<2> `ConfigSources.create(Supplier...)` creates and returns a -`CompositeBuilder` based on the two sources. -<3> Specifies a particular executor for monitoring and change event notification. -<4> Sets the subscriber's buffer size to 4 events. The composite source discards -any events not consumed by a subscriber if it needs to create room for more -recent events. -<5> Change events will not fire more frequently than once per a second. - -=== Config Custom Executor -A loaded config tree subscribes to change events publishes by its source(s). -By default, each `Config` uses an executor which manages a dedicated thread pool -reusing previously-created threads when they are available and creating new threads -as needed. -All `Config` instances share the dedicated thread pool. - -Your application -can specify a non-default `Executor` for a tree to use for accepting and propagating -those events by invoking the `changesExecutor` method on the `Config.Builder`. -Each source subscriber has a dedicated buffer for holding changes events. This -defaults to 256, but you can tailor this value as needed. - -[source,java] -.Customize config executor ----- -Executor executor = Executors.newCachedThreadPool(); // <1> - -Config config = Config.create( - file("conf/config.properties") - .pollingStrategy(PollingStrategies::watch)) - .changesExecutor(executor) // <2> - .changesMaxBuffer(16) // <3> - .build(); ----- - -<1> Prepares a specific thread pool executor. -<2> Specifies the executor the `Config` tree will use to listen for and propagate -change events. -<3> Sets the event subscriber buffer to `16` events. - === Retry Policy Custom Executor You can control which executor a retry policy should use for its work. The `RetryPolicies.repeat(int retries)` method returns diff --git a/docs/se/config/config-profiles.adoc b/docs/se/config/config-profiles.adoc index e3e86f36b97..5a8d1f0df7a 100644 --- a/docs/se/config/config-profiles.adoc +++ b/docs/se/config/config-profiles.adoc @@ -279,9 +279,11 @@ accompanying `properties`. |Type |Usage |Properties |`file` -| Filesystem monitoring - See link:{config-javadoc-base-url}/io/helidon/config/PollingStrategies.html#watch-java.nio.file.Path-[`PollingStrategies.watch`] method +| Filesystem monitoring - See link:{config-javadoc-base-url}/io/helidon/config/FileSystemWatcher.html[`FileSystemWatcher`] class | `initial-delay-millis` - delay between the start of the watcher and first check for changes +`delay-millis` - how often do we check the watcher service for changes + |=== .Config Profile Support for Built-in Retry Policies @@ -311,6 +313,6 @@ You can then use any custom properties - these are provided as a `Config` instan the `create` method of the Provider implementation. See link:{config-javadoc-base-url}/io/helidon/config/spi/RetryPolicy.html[`RetryPolicy`], -link:{config-javadoc-base-url}/io/helidon/config/spi/RetryPolicy.html[`ChangeWatcher`], and +link:{config-javadoc-base-url}/io/helidon/config/spi/ChangeWatcher.html[`ChangeWatcher`], and link:{config-javadoc-base-url}/io/helidon/config/spi/PollingStrategy.html[`PollingStrategy`] JavaDoc sections. \ No newline at end of file diff --git a/docs/se/config/property-mapping.adoc b/docs/se/config/property-mapping.adoc index 1c60b1fa44d..983f98a857a 100644 --- a/docs/se/config/property-mapping.adoc +++ b/docs/se/config/property-mapping.adoc @@ -489,7 +489,7 @@ object from the config data. By default, the system matches potential JavaBean property names with config keys in the configuration. -Use the link:{config-javadoc-base-url}/io/helidon/config/Value.html[`Value`] annotation to control some of JavaBean processing for a given property. +Use the link:{config-mapping-javadoc-base-url}/io/helidon/config/objectmapping/Value.html[`Value`] annotation to control some of JavaBean processing for a given property. .`Value` Annotation |=== @@ -501,7 +501,7 @@ Use the link:{config-javadoc-base-url}/io/helidon/config/Value.html[`Value`] ann |=== To exclude a bean property from the config system bean processing annotate it with -link:{config-javadoc-base-url}/io/helidon/config/Config.Transient.html[`Config.Transient`]. +link:{config-mapping-javadoc-base-url}/io/helidon/config/objectmapping/Transient.html[`Transient`]. Here is an example using the `app` portion of the example configuration from the introduction. @@ -543,7 +543,7 @@ public class AppConfig { return basicRange; } - @Config.Transient // <7> + @Transient // <7> public void setTimestamp(Instant timestamp) { this.timestamp = timestamp; } diff --git a/docs/se/config/supported-formats.adoc b/docs/se/config/supported-formats.adoc index 3797d949fa1..6d9c9d8b9ed 100644 --- a/docs/se/config/supported-formats.adoc +++ b/docs/se/config/supported-formats.adoc @@ -91,21 +91,21 @@ which the Helidon YAML parser matches. .YAML parser specified - no file type on source ---- Config config = Config.create(classpath("my-config") // <1> - .parser(YamlConfigParserBuilder.buildDefault())); // <2> + .parser(YamlConfigParser.create())); // <2> ---- <1> The media type of the source `my-config` is unknown, so the config system cannot choose a parser automatically. <2> The config system will parse the resource `my-config` on the runtime classpath using the YAML parser instance created by the -link:{config-javadoc-base-url}/io/helidon/config/yaml/YamlConfigParserBuilder.html[`YamlConfigParserBuilder`]. -The `buildDefault()` method creates a config parser with default behavior. +link:{config-javadoc-base-url}/io/helidon/config/yaml/YamlConfigParser.html[`YamlConfigParser`]. +The `create()` method creates a config parser with default behavior. [source,java] .Media type specified ---- Config config = Config.create(classpath("my-config") // <1> - .mediaType("application/x-yaml")); // <2> + .mediaType(MediaTypes.APPLICATION_X_YAML)); // <2> ---- <1> The media type of the source `my-config` is unknown, so the config system @@ -118,7 +118,7 @@ use its matching algorithm with the available parsers to choose a parser for tha ---- Config config = Config.builder(classpath("application.yaml")) .disableParserServices() // <1> - .addParser(YamlConfigParserBuilder.buildDefault()) // <2> + .addParser(YamlConfigParser.create()) // <2> .build(); ---- @@ -185,7 +185,7 @@ The `create()` method creates a config parser with default behavior. .Media type specified ---- Config config = Config.create(classpath("my-config") // <1> - .mediaType("application/hocon")); // <2> + .mediaType(MediaTypes.APPLICATION_HOCON)); // <2> ---- <1> The media type of the source `my-config` is unknown, so the config system @@ -254,19 +254,19 @@ module myModule { ==== Using the Etcd Config Source To read configuration from an Etcd source, your application uses the -link:{config-javadoc-base-url}/io/helidon/config/etcd/EtcdConfigSourceBuilder.html[`EtcdConfigSourceBuilder`]. +link:{config-etcd-javadoc-base-url}/io/helidon/config/etcd/EtcdConfigSourceBuilder.html[`EtcdConfigSourceBuilder`]. [source,java] .Use Etcd config source ---- Config config = Config.create( - EtcdConfigSourceBuilder // <1> + EtcdConfigSource // <1> .create(URI.create("http://my-etcd:2379"), // <2> "/config.yaml", // <3> EtcdConfigSourceBuilder.EtcdApi.v3)); // <4> ---- -<1> Use the factory method `EtcdConfigSourceBuilder.create` to initialize the builder. +<1> Use the factory method `EtcdConfigSource.create` to create the `EtcdConfigSource`. <2> Specify the Etcd endpoint address. <3> Specify the Etcd key of the configuration document. <4> Version of the Etcd API to use; `v3` is supported. `v2` is deprecated. @@ -275,29 +275,29 @@ The config system will use the <> automatically i because the file type of the key is `.yaml`. The `EtcdConfigSourceBuilder` class extends -link:{config-javadoc-base-url}/io/helidon/config/spi/AbstractParsableConfigSource.Builder.html[`AbstractParsableConfigSource.Builder`] +link:{config-javadoc-base-url}/io/helidon/config/spi/AbstractConfigSourceBuilder.html[`AbstractConfigSourceBuilder`] and so supports the usual settings on config sources. ==== Monitoring for Source Changes -The Etcd support includes a polling strategy designed for an etcd config source. +The Etcd support includes a change watcher strategy designed for an etcd config source. [source,java] .Use Etcd config source ---- Config config = Config.create( - EtcdConfigSourceBuilder - .create(URI.create("http://my-etcd:2379"), "/config.yaml", EtcdApi.v3) - .pollingStrategy(EtcdWatchPollingStrategy::new)); // <1> + EtcdConfigSource + .builder() + .uri(URI.create("http://my-etcd:2379")) + .key("/config.yaml") + .api(EtcdConfigSourceBuilder.EtcdApi.v3) + .changeWatcher(EtcdWatcher.create())); // <1> ---- -<1> Use the etcd-specific polling strategy. +<1> Use the etcd-specific change watcher strategy. ==== Loading Meta-configuration via Etcd -The config system can load information about config sources from -xref:advanced-configuration.adoc#Config-Advanced-Config-MetaConfig[meta-configuration] -rather than requiring your application to construct the builder. To read -meta-configuration from an Etcd source set the following required properties +To read meta-configuration from an Etcd source set the following required properties for the source: * `type` to `etcd`, or `class` to `io.helidon.config.etcd.EtcdConfigSourceBuilder` @@ -307,8 +307,8 @@ for the source: version. `v2` is deprecated. Other optional `properties` are inherited from - `AbstractParsableConfigSource.Builder`. (see -link:{config-javadoc-base-url}/io/helidon/config/spi/AbstractParsableConfigSource.Builder.html#init-io.helidon.config.Config-[javadoc]) + `AbstractConfigSourceBuilder`. (see +link:{config-javadoc-base-url}/io/helidon/config/AbstractConfigSourceBuilder.html#init-io.helidon.config.Config-[javadoc]) [source,java] .Load Config from meta-configuration @@ -325,14 +325,14 @@ sources: uri: "http://my-etcd:2379" # <2> key: "/config.yaml" # <2> api: "v3" # <2> - polling-strategy: - class: "io.helidon.config.etcd.EtcdWatchPollingStrategy" # <3> + change-watcher: + type: "etcd" # <3> ---- <1> `etcd` config source type <2> Etcd source-specific (mandatory) `properties`: `uri`, `key` and `api`. -<3> Polling strategy `EtcdWatchPollingStrategy` is automatically initialized by +<3> Watcher strategy `EtcdWatcher` is automatically initialized by specified mandatory `properties`. === git [[Config-ModuleGit]] @@ -360,21 +360,20 @@ module myModule { ==== Using the git Config Source To read configuration from a git source, your application uses the -link:{config-javadoc-base-url}/io/helidon/config/git/GitConfigSourceBuilder.html[`GitConfigSourceBuilder`]. +link:{config-git-javadoc-base-url}/io/helidon/config/git/GitConfigSourceBuilder.html[`GitConfigSourceBuilder`]. [source,java] .Use git config source ---- Config config = Config.create( - GitConfigSourceBuilder - .create("application.conf") // <1> - .uri(URI.create("https://github.com/okosatka/test-config.git")) // <2> - .directory(Paths.get("/config")) // <3> - .branch("dev")); // <4> + GitConfigSource + .builder() // <1> + .uri(URI.create("https://github.com/okosatka/test-config.git")) // <2> + .directory(Paths.get("/config")) // <3> + .branch("dev")); // <4> ---- -<1> Use the factory method `GitConfigSourceBuilder.create` to initialize the builder - with a mandatory path to the configuration file. +<1> Use the factory method `GitConfigSource.builder` to initialize the builder. <2> Specify the git repository URI. <3> Specify a directory where the git repository is already cloned or it will be cloned. <4> Specify the git branch. @@ -385,7 +384,7 @@ HOCON config module must be on module-path or classpath. The `GitConfigSourceBuilder` supports the usual source builder properties because it extends -link:{config-javadoc-base-url}/io/helidon/config/spi/AbstractParsableConfigSource.Builder.html[`AbstractParsableConfigSource.Builder`]. +link:{config-javadoc-base-url}/io/helidon/config/AbstractConfigSourceBuilder.html[`AbstractConfigSourceBuilder`]. ==== Monitoring for Source Changes Your application can monitor changes to a configuration loaded from a git source diff --git a/docs/se/guides/config.adoc b/docs/se/guides/config.adoc index 68cbd0927a4..08ba811765f 100644 --- a/docs/se/guides/config.adoc +++ b/docs/se/guides/config.adoc @@ -86,7 +86,7 @@ In your application code, Helidon uses the default configuration when you create See the following code from the project you created. [source,Java] -.View `Main.startServer`: +.View `Main.main`: ---- Config config = Config.create(); // <1> ---- @@ -145,14 +145,15 @@ curl http://localhost:8080/greet ---- <1> The new `app.greeting` value in `application.yaml` is used. -===== System Property Override +===== Environment Variable Override -A system property has a higher precedence than `application.yaml`. +A environment property has a higher precedence than `application.yaml`. [source,bash] -.Restart the application with a system property. The `app.greeting` environment variable is still set: +.Set the environment variable and restart the application: ---- -java -Dapp.greeting="HelloFromSystemProperty" -jar target/helidon-quickstart-se.jar +export APP_GREETING=HelloFromEnvironment +java -jar target/helidon-quickstart-se.jar ---- [source,bash] @@ -164,20 +165,20 @@ curl http://localhost:8080/greet [source,json] ---- { - "message": "HelloFromSystemProperty World!" // <1> + "message": "HelloFromEnvironment World!" // <1> } ---- -<1> The system property took precedence over `application.yaml`. +<1> The environment property took precedence over `application.yaml`. -===== Environment Variable Override +===== System Property Override -An environment variable has a higher precedence than the system property. +An system variable has a higher precedence than the environment property. [source,bash] -.Set the environment variable and restart the application: +.Restart the application with a system property. The `APP_GREETING` environment variable is still set: ---- export APP_GREETING=HelloFromEnvironment -java -Dapp.greeting="HelloFromSystemProperty" -jar target/helidon-quickstart-se.jar +java -Dapp.greeting="HelloFromSystemProperty" -jar target/helidon-quickstart-se.jar ---- [source,bash] @@ -189,10 +190,10 @@ curl http://localhost:8080/greet [source,json] ---- { - "message": "HelloFromEnvironment World!" // <1> + "message": "HelloFromSystemProperty World!" // <1> } ---- -<1> The environment variable `APP_GREETING` took precedence over the system property and the value in `application.yaml`. +<1> The system variable `app.greeting` took precedence over the environment property and the value in `application.yaml`. == Custom Configuration Sources @@ -237,7 +238,7 @@ app.greeting=HelloFrom-config.properties import static io.helidon.config.ConfigSources.classpath; // <1> //... - static WebServer startServer() throws IOException { + public static void main(final String[] args) { //... Config config = buildConfig(); // <2> @@ -564,8 +565,8 @@ key can be composite as shown below: [source,java] .View the `GreetService` constructor: ---- - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); // <1> + GreetService() { + greeting.set(Config.global().get("app.greeting").asString().orElse("Ciao")); // <1> } ---- <1> Get the `app.greeting` node using a composite key. @@ -575,8 +576,8 @@ You can also access the same greeting by navigating the nodes. [source,java] .Replace the `GreetService` constructor with the following code: ---- - GreetService(Config config) { - greeting.set(config.get("app").get("greeting").asString().orElse("Ciao")); // <1> + GreetService() { + greeting.set(Config.global().get("app").get("greeting").asString().orElse("Ciao")); // <1> } ---- <1> Get the `app` node, then get the child node, `greeting`. @@ -625,11 +626,12 @@ app: import java.util.List; import java.util.stream.Collectors; - GreetService(Config config) { - List appGreetings = config.get("app") + GreetService() { + List appGreetings = Config.global() + .get("app") .traverse() // <2> .filter(node -> node.name().equals("greeting")) // <3> - .collect(Collectors.toList()); // <4> + .toList(); // <4> greeting.set(appGreetings.get(0).asString().get()); } @@ -678,10 +680,10 @@ sources: import java.util.function.Consumer; ... - GreetService(Config config) { - Config greetingConfig = config.get("app.greeting"); // <1> + GreetService() { + Config greetingConfig = Config.global().get("app.greeting"); // <1> greeting.set(greetingConfig.asString().orElse("Ciao")); - greetingConfig.onChange((Consumer) cfg -> greeting.set(cfg.asString().orElse("Ciao"))); // <2> + greetingConfig.onChange(cfg -> greeting.set(cfg.asString().orElse("Ciao"))); // <2> } ---- <1> Get the greeting `Config` node. @@ -749,8 +751,8 @@ app: [source,java] .Replace the `GreetService` constructor with the following code: ---- - GreetService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); + GreetService() { + greeting.set(Config.global().get("app.greeting").asString().orElse("Ciao")); } ---- From 7617f8a52c8bbd0fce55db90e167fb6935e6573f Mon Sep 17 00:00:00 2001 From: David Kral Date: Wed, 18 Oct 2023 16:04:19 +0200 Subject: [PATCH 2/2] comments addressed Signed-off-by: David Kral --- docs/se/config/advanced-configuration.adoc | 9 ++++----- docs/se/guides/config.adoc | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/se/config/advanced-configuration.adoc b/docs/se/config/advanced-configuration.adoc index 31b80d4236b..f35f418c488 100644 --- a/docs/se/config/advanced-configuration.adoc +++ b/docs/se/config/advanced-configuration.adoc @@ -255,10 +255,9 @@ sources gives your application a way to access all config elements distinctly ev if their keys would otherwise conflict. ===== Merging Strategies -When creating config from multiple sources it is possible, that the same key comes from multiple -sources. By default, earlier sources in the list have higher priority than later ones, meaning -that if the same key appears in two or more sources the source earlier in the -list prevails. +When creating config from multiple sources, it is possible that the same key comes from multiple +sources. By default, earlier sources in the list have higher priority than later ones. This means +that if the same key appears in two or more sources, then the source earlier in the list prevails. The config system provides the `FallbackMergingStrategy` @@ -624,7 +623,7 @@ Each of these uses an executor to perform its work. The config system provides d executors, but your application can specify different ones if necessary. === Executors for Polling Strategy -The method `PollingStrategies.regular(Duration)` return builder for polling strategy. +The method `PollingStrategies.regular(Duration)` returns builder for polling strategy. This builder provides `executor` method which your application can invoke, passing a `java.util.concurrent.ScheduledExecutorService` instance it requires for the polling work. By default, each polling strategy instance uses a separate thread diff --git a/docs/se/guides/config.adoc b/docs/se/guides/config.adoc index 08ba811765f..92ffd94d1b1 100644 --- a/docs/se/guides/config.adoc +++ b/docs/se/guides/config.adoc @@ -147,7 +147,7 @@ curl http://localhost:8080/greet ===== Environment Variable Override -A environment property has a higher precedence than `application.yaml`. +An environment property has a higher precedence than `application.yaml`. [source,bash] .Set the environment variable and restart the application: @@ -172,7 +172,7 @@ curl http://localhost:8080/greet ===== System Property Override -An system variable has a higher precedence than the environment property. +A system variable has a higher precedence than the environment property. [source,bash] .Restart the application with a system property. The `APP_GREETING` environment variable is still set: