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

    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

= Mutability Support
:description: Helidon mutability support
:keywords: helidon, config

An in-memory config tree, once loaded, is immutable, even though the data in the underlying
config sources _can_ change over time. Your application can find out metadata about a 
loaded in-memory config and can track changes in config sources.

== Overview
Even though in-memory config trees are immutable, the config system internally
records which config sources it used to load each config tree and some metadata
about the configuration. Your application can be aware of updates to the underlying
config sources by:

1. using the metadata the config system maintains,
2. responding to changes when the config sources are updated, or
3. using ``Supplier``s of particular config values to obtain the always-current
value for a key.

== Using Config Metadata
=== Loading Time
The config system records when it loads each configuration into memory. 
Your application can retrieve it by invoking the link:{javadoc-base-url-api}/Config.html#timestamp--[timestamp method]:
[source,java]
java.time.Instance loadTime = myConfig.timestamp();

on any config node.

=== Config Context
The config system maintains a link:{javadoc-base-url-api}/Config.Context.html[`Config.Context`] 
for each `Config` node. Your application can retrieve the context by invoking the `Config.context()`
method and then use it for these operations:

.Uses of `Config.Context`
|===
|Method |Usage

|`Instant timestamp()` |Returns the load time of the last loaded configuration
that used the context.
|`Config last()` |Returns the most recently loaded configuration that used the context.
|`Config reload()` |Reloads the
entire config tree from the current contents of the same config sources used to 
load the tree in which the current node resides.
|===

Note that the config context describes or replaces a currently-loaded config tree. 
It by itself does not help your application decide _when_ reloading the config might be
useful.

== Responding to Changes in Config Sources [[polling]]
[IMPORTANT]
.Evolving API
====
This section describes the `Config.changes()` method. It is marked
as deprecated because it returns an `io.helidon.reactive.Flow.Publisher` object.
In a future Helidon release that requires Java 9 or later this method will be undeprecated 
and changed -- or a similar method will be added -- so that the return type is
`java.util.concurrent.Flow.Publisher` instead. 

Any code you write using the existing `Config.changes()` method might need
to change at that time. 
====

Although in-memory config trees do not change once loaded, applications can respond to changes 
in the underlying config sources by:

1. setting up change detection for the config sources used to build a configuration, and
2. registering a response to be run when a source changes.

Your code's response can react to the changes in whatever way makes sense 
for your application.

The following sections describe these steps in detail.

=== Setting up Config Source Change Detection
When the application creates a config source, it can set up change detection for
that source. This is called _polling_ in the Helidon API but specific change detection
algorithms might not use actual polling. You choose a specific
link:{javadoc-base-url-api}/spi/PollingStrategy.html[`PollingStrategy`] for each
config source you want to monitor. See the section on 
<<config/07_extensions.adoc#Config-SPI-PollingStrategy,polling strategies>> in the
config extensions doc page for more information.

The config system provides some built-in polling strategies, exposed as these methods
on the link:{javadoc-base-url-api}/PollingStrategies.html[`PollingStrategies`] class:

- `regular(Duration interval)` - a general-purpose scheduled polling strategy with a specified,
 constant polling interval.
- `watch(Path watchedPath)` - a filesystem-specific strategy to watch
 specified path. You can use this strategy with the `file` and `classpath` 
built-in config sources.
- `nop()` - a no-op strategy

This example builds a `Config` object from three sources, each set up with a
different polling strategy:

[source,java]
.Build a `Config` with a different `PollingStrategy` for each config source
----
Config config = Config.create(
        ConfigSources.file("conf/dev.properties")
                .pollingStrategy(PollingStrategies.regular(Duration.ofSeconds(2))) // <1>
                .optional(),
        ConfigSources.file("conf/config.properties")
                .pollingStrategy(PollingStrategies::watch)                         // <2>
                .optional(),
        ConfigSources.classpath("application.properties")
                .pollingStrategy(PollingStrategies::nop));                         // <3>
----

<1> Optional `file` source `conf/dev.properties` will be checked for changes every
 `2` seconds.
<2> Optional `file` source `conf/config.properties` will be watched by the Java
 `WatchService` for changes on filesystem.
<3> The `classpath` resource `application.properties` will not be checked for
 changes. 
`PollingStrategies.nop()` polling strategy is default.

The polling strategies internally inform the config system when they
detect changes in the monitored config sources (except that the `nop` strategy does
nothing). 

=== Registering a Config Change Response
To know when config sources have changed, your application must register its interest 
on the `Config` node of interest. The config system will then notify
your application of any change within the subtree rooted at that node. 
In particular, if you register on the root node,
then the config system notifies your code of changes anywhere in the config tree.

You can register in either of two ways:

1. register an action to be run upon each change, or
2. subscribe to a `Flow.Publisher` that notifies of changes.

==== Registering Actions
A simple approach is for your application to register a function that should
run when any change occurs.

[source,java]
.Subscribe on `greeting` property changes via `onChange` method
----
config.get("greeting")                                                         // <1>
        .onChange((changedNode) -> {                                           // <2>
            System.out.println("Node " + changedNode.key() + " has changed!");
            return true;                                                       // <3>
        });
----

<1> Navigate to the `Config` node on which you want to register.
<2> Invoke the `onChange` method, passing a function (`Function<Config, Boolean>`).
The config system invokes that function each time the subtree rooted at the
`greeting` node changes. The `changedNode` is a new instance of `Config` 
representing the updated subtree rooted at `greeting`. 
<3> The function should return `true` to continue being run on subsequent changes, `false`
to stop.

==== Subscribing to Events
The config system also supports the flow publisher/subscriber model for applications
that need more control over the pace at which the config system delivers
config change events.

Each `Config` instance exposes the link:{javadoc-base-url-api}/Config.html#changes--[`Config.changes()`]
method which returns a `Flow.Publisher<Config>`.
Your application can invoke this method, then invoke `subscribe` on the returned 
`Flow.Publisher`, passing your own `Flow.Subscriber` implementation. The config system will
invoke your subscriber's methods as appropriate, most notably calling `onNext` 
whenever it detects a change in one of the underlying config sources for the config
node of interest.

Mote that your subscriber will be notified when a change occurs anywhere in the 
subtree represented by the `Config` node. 

[source,java]
.Subscribe on `greeting` property changes
----
config.get("greeting")                                                             // <1>
        .changes()                                                                 // <2>
        .subscribe(new Flow.Subscriber<>() {                                       // <3>
            Flow.Subscription subscription;

            @Override
            public void onSubscribe(Flow.Subscription subscription) {              // <4>
                this.subscription = subscription;
                subscription.request(1);
            }

            @Override
            public void onNext(Config changedNode) {                               // <5>
                System.out.println("Node " + changedNode.key() + " has changed!");
                subscription.request(1);
            }

            @Override
            public void onError(Throwable throwable) {                             // <6>
            }

            @Override
            public void onComplete() {                                             // <7>
            }
        });
----

<1> Navigate to the `Config` node on which you want to register.
<2> Invoke `changes` to get the `Flow.Publisher` of changes to the subtree rooted
at the `Config` node.
<3> Subscribe to the publisher passing a custom `Flow.Subscriber<Config>` implementation.
<4> Request the first event delivery in `onSubscribe` method.
<5> The config system invokes `onNext` each time the subtree rooted at the 
`greeting` node changes. The `changedNode` is a new instance of `Config` representing
the updated subtree rooted at `greeting`, regardless of where in the subtree
the change actually occurred. Remember to request the next event delivery in `onNext`.
<6> The config system does not currently invoke `onError`.
<7> The config system invokes `onComplete` if all config sources indicate _there will
 be no other change event_. 

[NOTE]
Your application _does not_ need to subscribe to the new `Config` instance passed
to your `onNext` method. The original subscription remains in force for changes
to the "new" instance.

== Accessing Always-current Values
Some applications do not need to respond to changes as they happen. Instead it's
sufficient that they simply have access to the current value for a particular
key in the configuration.

Each `asXXX` method on the `Config` class has a companion `asXXXSupplier` method. 
These supplier methods return `Supplier<XXX>`, and when your application invokes 
the supplier's `get` method the config system returns the _then-current value_ 
as stored in the config source.

[source,java]
.Access `greeting` property as `Supplier<String>`
----
// Construct a Config with the appropriate PollingStrategy on each config source.

Supplier<String> greetingSupplier = config.get("greeting")                     // <1>
        .asString().supplier();                                                   // <2>

System.out.println("Always actual greeting value: " + greetingSupplier.get()); // <3>
----
<1> Navigate to the `Config` node for which you want access to the always-current
value.
<2> Retrieve and store the returned supplier for later use. 
<3> Invoke the supplier's `get()` method to retrieve the current value of the node.

[IMPORTANT]
=========
Supplier support requires that you create the `Config` object from config sources that
have proper polling strategies set up. 
=========
