///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.

    Licensed 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.

///////////////////////////////////////////////////////////////////////////////

:javadoc-base-url-api: {javadoc-base-url}?io/helidon/config

= The Configuration Component
:description: Helidon config introduction
:keywords: helidon, config

The config component provides a Java API to load and process
configuration properties in key/value form into a `Config` object which the
application can use to retrieve config data.

== Getting Started

=== Introducing the Config System
A brief overview of the config system helps clarify its different parts
and how they work together. Most applications will typically deal with more
than one of these parts.

image::config/overview.png["Configuration Overview",align="center"]

The system reads configuration from a _config source_, a physical location (such as a file,
a URL, or a `String`) which holds config data. Each config source works with a 
_config parser_ which translates a particular text format (for example, Java properties or YAML)
into an in-memory tree which represents the configuration's structure and values.
An optional _polling strategy_ detects and publishes changes to the underlying config source
so the config source itself or your application can respond.

Your application uses the `Config` 
object which results from building that in-memory tree to retrieve config data. 
The app can navigate explicitly among the nodes in the tree and fetch a node's
value
[source,java]
----
int pageSize = config
                .get("web")
                .get("page-size")
                .asInt()
                .orElse(20);
----
or it can address a node in the tree using the config key's dotted name 
[source,java]
----
int pageSize = config
                .get("web.page-size")
                .asInt()
                .orElse(20);
----
As part of
retrieving a value from a node, the config system applies _config filters_
which can change what values are returned for selected keys. 

The `Config` object lets your application retrieve config data as a typed ConfigValue.

ConfigValue<T> can be used to obtain:
* an `Optional<T>` value _from a single node_,
* the `T` value _from a single node_ interpreted as a basic Java type
(primitive or simple object) already known to the config system (such as
a `boolean` or a `Double`), or
* a complex Java type _from a subtree_ of the config tree.
+
The config system automatically knows how to return `List` and `Map` complex types, 
and you can provide _config mappers_ to convert a config subtree to whatever
Java types your application needs.

=== Your First Config Application
An easy way to start with the link:{javadoc-base-url-api}/Config.html[Config] API
is to follow these four steps:

1. <<maven-coords,add config-related dependencies to your `pom.xml`>>
2. <<update-module-info, revise your `module-info.java` to refer to config (if you are using Java 9)>>
3. <<create-simple-config-props, create a simple config properties file>>
4. <<Config-Basics-DefaultConfig, retrieve and use the default `Config` from your app>>

==== Add Maven Dependency on Config [[maven-coords]]
[source,xml]
.Config Dependency in `pom.xml`
----
<dependencies>
    <dependency>
        <groupId>io.helidon.config</groupId>
        <artifactId>helidon-config</artifactId>
        <version>version-of-config-you-are-using</version>
    </dependency>
</dependencies>
----

==== Update `module-info.java` [[update-module-info]]
If you are using Java 9 then create or update the `module-info.java` file for your application:
[source,java]
.Config Dependency in `module-info.java`
----
module myModule {
    requires io.helidon.config;
}
----

==== Create simple Config Properties File [[create-simple-config-props]]
[source]
.Example `src/main/resources/application.properties` config file
----
greeting = Hello

web.debug = true
web.page-size = 20
web.ratio = 1.3

bl.initial-id = 10000000000

origin = props
java.home=homeFromProps # will be ignored
----

==== Write Code using the Default Config [[Config-Basics-DefaultConfig]]

[source,java]
.Create and Use Default `Config` from Java
----
import io.helidon.config.Config; // <1>
...
Config config = Config.create(); // <2>
System.out.println(String.format(
        "greeting is %s\n"
                + "web.debug is %b\n"
                + "web.page-size is %d\n"
                + "web.ratio is %f\n"
                + "bl.initial-id is %d\n"
                + "origin is %s\n"
                + "java.home is %s",
        config.get("greeting").asString().orElse("Default greeting"),  // <3>
        config.get("web.debug").asBoolean().orElse(false),
        config.get("web.page-size").asInt().orElse(50),
        config.get("web.ratio").asDouble().orElse(2.0),
        config.get("bl.initial-id").asLong().orElse(1L),
        config.get("origin").asString().orElse("defaults"),
        config.get("java.home").asString().get())); // <4>
----
<1> Import `Config`.
<2> Create the root of the `Config` tree from the default sources.
<3> Retrieve various values by their dotted names and decode them as the appropriate 
Java types, providing default values if the property is missing.
<4> Retrieve the value (and fail with a runtime exception if missing)
 
When you build and run your project, the output will look like this:
[source]
----
greeting is Hello
web.debug is true
web.page-size is 20
web.ratio is 1.300000
bl.initial-id is 10000000000
origin is props
java.home is /Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
----

===== Config Sources for the Default Config [[config-sources-default-config]]
The default config uses the following config sources, listed here from most to least important:

. Java system properties
. Environment variables
. `application.properties`, if on the classpath.

The priority (most to least important) means that if a given config key appears in
more than one source, the value assigned in a more important source overrules the
value from a less important source.

Verify this by noting that the program has displayed your actual `java.home` which
Java set as a system property, not the value set in the example `application.properties`
file.

===== Built-in Support for Config Formats [[built-in-formats]]
If you add additional Helidon config maven artifacts to your dependencies, then the
config system can read formats other than Java properties format and the default
configuration will search for other `application` file types 
in the following order. Note that the default configuration _stops_ once it finds
one of the files below; it _does not_ merge all such files it can find.

.Default Config Files (most to least important)
|===
|Source |Helidon maven artifact ID (group ID: `io.helidon.config`) |Notes

|`application.yaml` |`helidon-config-yaml` |YAML format http://yaml.org
|`application.conf` |`helidon-config-hocon` |HOCON format https://github.com/lightbend/config#using-hocon-the-json-superset
|`application.json` |`helidon-config-hocon` |JSON format https://json.org/
|`application.properties` |`helidon-config` |Java properties format
|===

== Next Steps
Although the default configuration is very simple to use, your
application can take as much control as it needs over

* loading configuration data,
* accessing the data once loaded, and
* extending and modifying the behavior of the config system.

You do this by:

* creating and invoking methods on a `Config.Builder` object to construct a `Config` instance
+
Using a builder, the application can control everything about how the config
system creates the resulting `Config` instance: config sources, parsers, polling strategy,
filters, overrides, mappers, whether or not environment variables and Java
system properties serve as config sources. The JavaDoc explains how to use the 
link:{javadoc-base-url-api}/Config.Builder.html[`Config.Builder`].
+
or
* creating a <<config/06_advanced-configuration.adoc#Config-Advanced-metaconfig,meta-configuration>>
file on the runtime classpath to control how the config system prepares the 
default configuration.

Once created, the `Config` object provides many methods the application can use to 
retrieve config data as various Java types. See the link:{javadoc-base-url-api}/Config.html[`Config`]
JavaDoc for complete details.

The links in the following tables lead you to more information about various 
other config topics.

.Controlling How Config is Loaded
|===
| Topic |Documentation

| Where config comes from |<<config/02_config-sources.adoc,Config sources>>,
<<config/06_advanced-configuration.adoc#metaconfig,meta-configuration>>
| What format config data is expressed in |<<config/02_config-sources.adoc#parsers,Config parsers>>, 
<<config/08_supported-formats.adoc,supported formats>>
| How to filter, override, and dereference values |<<config/06_advanced-configuration.adoc#filters-and-overrides,Filters and overrides>>
| What happens when config data changes |<<config/05_mutability-support.adoc#polling,Config polling>>
| How to deal with loading errors |<<config/02_config-sources.adoc#retry,Config retry policies>>
|===

.Accessing Configuration Data
|===
| Topic |Documentation

| How config data is translated into Java types |<<config/04_property-mapping.adoc,Config mappers>>
| How to navigate config trees |<<config/03_hierarchical-features.adoc,Navigation>>
|===

.Extending and Fine-tuning the Config System
|===
| Topic |Documentation 

| Writing extensions |<<config/07_extensions.adoc,Extensions>>
|===

////

The `Config` API covers the following use cases:

- *accessors* - The basic value type is `String`, and accessor methods 
 map a value into `boolean`, `int`, `long`, `double`. You can also use
 `Optional` variants of accessor methods.
- *mappers* - You can map a single value or a complex Config node
 into a custom Java type.
- *tree-like structure* - The configuration tree 
includes  _object_ and _list_ configuration node types.
- *watchers* - You can subscribe to source changes.

The Configuration `Builder` API lets you build a new instance of `Config` and bootstrap
 it using appropriate SPI (Service Provider Interface) implementations.

The Config component supports the following SPIs:

- *config source* - implement a custom mechanism to load configuration
 raw data from any source.
- *config parser* - provide a custom configuration format parser.
- *config filter* - filter configuration values before it will be
 accessible via Config API.
- *config overrides* - allows overriding existing configuration values with new
 ones. Keys are specified by wildcards.
- *config mapper provider* - register a custom config mapper
 implementation to map a configuration value or hierarchy to a Java type.







[NOTE]
=========
The advanced feature of loading the configuration from an externalized list of sources
 (also known as meta-configuration) by the `Config.create()` method is described in
 <<config/06_advanced-configuration.adoc#Config-Advanced-Config-MetaConfig,Create Config from meta-configuration>>.
=========


Let's walk through an example. This
 `application.properties` file is on the application classpath.

[source,properties] <<app-properties-example>>
.`application.properties` file
----
greeting = Hello

web.debug = true
web.page-size = 20
web.ratio = 1.3

bl.initial-id = 10000000000

----

Let's get the `greeting`
 property value from the loaded configuration.

[source,java]
.Retrieve configuration property as a `String`
----
String greeting = config
        .get("greeting") // <1>
        .asString();     // <2>

System.out.println("greeting: " + greeting);
assert greeting.equals("Hello");
----

<1> retrieve configuration node that represents the `greeting`
 property.
<2> return the property value as a `String`.

You can override the value loaded from
 `application.properties` by system properties or by environment variables
 (the top priority).

[source,sh]
.Override `greeting` value using Java system property
----
java -Dgreeting=Hi -jar app-fat.jar
----

In this case, `greeting: Hi` is printed to console.

[source,sh]
.Override `greeting` value by environment variable
----
greeting=Ciao java -Dgreeting=Hi -jar app-fat.jar
----

`greeting: Ciao` is printed to console, even if the Java system
 property is also used.

== Working with different types

Not all configuration properties are `String` types. You can also get a
 property value as `boolean`, `int`, `long`, `double`, etc. 

[source,java]
.Access configuration properties values as different Java types
----
boolean debug = config.get("web.debug").asBoolean();   // <1>
assert debug == true;

int pageSize = config.get("web.page-size").asInt();    // <2>
assert pageSize == 20;

double ratio = config.get("web.ratio").asDouble();     // <3>
assert ratio == 1.3;

long initialId = config.get("bl.initial-id").asLong(); // <4>
assert initialId == 10000000000L;
----

<1> Method `asBoolean()` returns `web.debug` property as a `boolean` value.
<2> Method `asInt()` returns `web.page-size` property as a `int` value.
<3> Method `asDouble()` returns `web.ratio` property as a `double` value.
<4> Method `asLong()` returns `bl.initial-id` property as a `long` value.

For more options, see 
 <<config/04_property-mapping.adoc,Property Mapping>>.

== Accessor Exceptions

Accessor methods can throw two exceptions:

. link:{javadoc-base-url-api}/MissingValueException.html[MissingValueException] is
 thrown if the `as*` method is invoked on a property that does not have a value set.
. link:{javadoc-base-url-api}/ConfigMappingException.html[ConfigMappingException]
 is thrown if a property can't be converted into the requested type.

[source,java]
.Requesting wrong property type
----
config.get("greeting")
        .asInt();      // <1>
----
<1> Property `greeting` cannot be mapped to `int`, so the 
 `asInt()` method throws `ConfigMappingException`.

[start=2]
[source,java]
.Accessing value on not set property
----
config.get("NOT-SET-PROPERTY")
        .asString();           // <1>
----
<1> Property `NOT-SET-PROPERTY` is missing, and the `asString()` method throws
 `MissingValueException`.


== Supplying default values

To avoid unset values, specify the default value of a property programmatically. 

[source,java]
.Specify default value 
----
String notSet = config.get("NOT-SET-PROPERTY")
        .asString("default-val");                  // <1>

assert notSet.equals("default-val");
----

<1> The `asString` method accepts a default value as the first parameter.

The same pattern is applied on each `as*` accessor method. 

The default value is ignored if the property exists.

[source,java]
.Specify default value for existing property
----
greeting = config.get("greeting")
        .asString("Ahoj");        // <1>

assert greeting.equals("Hello");  // <2>
----

<1> Specify default value for `greeting` property.
<2> The `greeting` property is loaded from `application.properties`.

////
