blob: 6aa0573dfc570796697de4d19157b27b1c11ea5c [file] [log] [blame]
:jbake-type: page
:jbake-status: published
= Apache Tamaya - Extension: Mutable Configuration
toc::[]
[[MutableConfiguration]]
== Tamaya Mutable Configuration (Extension Module)
Tamaya _Mutable Configuration_ is an extension module. Refer to the link:../extensions.html[extensions documentation] for further details.
=== What functionality this module provides ?
Tamaya +Configuration+ by default is read-only, which covers must of the use cases. But there are many legit scenarios
where configuration should be written back to backend systems or the local file system. This module adds this
functionality.
=== Compatibility
The module is based on Java 8.
=== Installation
To benefit from configuration mutability support you only must add the corresponding dependency to your module:
[source, xml, subs=attributes+]
-----------------------------------------------
<dependency>
<groupId>org.apache.tamaya.ext</groupId>
<artifactId>tamaya-mutable-config</artifactId>
<version>{tamaya_version}</version>
</dependency>
-----------------------------------------------
=== Core Architecture
==== Accessing MutableConfiguration
The core of the module is the +MutableConfiguration+ interface, which provides access to +MutableConfiguration+
instance, which extends +Configuration+. This interface adds additional methods to add/update or remove property values.
Hereby each +MutableConfiguration+ manages a transaction like context, which includes
a UUID that identifes a change.
Backends for writing changes applied umst implement +MutablePropertySource+, which extends +PropertySource+.
Registrations and ordering policies are exact the same as with ordinary property sources, but
mutable property sources can be targeted by config write operations.
The example below shows how a +MutableConfiguration+ can be obtained ,values added, removed and
finally changes written back to the backend:
[source,java]
.Accessing and changing configuration
--------------------------------------------
MutableConfiguration config = MutableConfiguration.create();
config.put("newKey", "newValue")
.put("anotherKey", "updatedValue")
.remove("valueNotValid")
.store();
--------------------------------------------
In the above scenario we use the system's _default_ configuration as the backend to be used.
We can also pass any +Configuration+ to render it into a mutable instance, e.g.
[source,java]
.Explicitly passing the backing configuration
--------------------------------------------
Configuration config = ...;
MutableConfiguration config = MutableConfiguration.create(config);
--------------------------------------------
NOTE: If a configuration does not contain any +MutablePropertySource+ instances,
a +ConfigurationException+ is thrown since it would not be able to accept
any changes.
Following we show the possible methods you can use to create a +MutableConfiguration+.
We will show in the following sections more details on the options provided...
[source, java]
---------------------------------------------
public interface MutableConfiguration extends Configuration {
void store();
ConfigChangeRequest getConfigChangeRequest();
ChangePropagationPolicy getChangePropagationPolicy();
MutableConfiguration put(String key, String value);
MutableConfiguration putAll(Map<String, String> properties);
MutableConfiguration remove(Collection<String> keys);
MutableConfiguration remove(String... keys);
public static MutableConfiguration create();
public static MutableConfiguration create(ClassLoader classLoader);
public static MutableConfiguration create(ChangePropagationPolicy changePropgationPolicy);
public static MutableConfiguration create(ChangePropagationPolicy changePropgationPolicy,
ClassLoader classLoader);
public static MutableConfiguration create(Configuration configuration);
public static MutableConfiguration create(Configuration configuration,
ChangePropagationPolicy changePropgationPolicy);
[...]
}
---------------------------------------------
===== Targeting specific MutablePropertySources
A +Configuration+ may have multiple +MutablePropertySource+ instances present. These are members of Tamaya's ordered list of
+PropertySources+ to evaluate the configuration. Nevertheless writing back changes requires additional aspects to
be considered:
* Should changes written target all mutable property sources? Or should a change only
target the most significant instance (hereby not writing the change to less significant property sources)?
* Or should a change be applied only to specific mutable property source(s), regardless its position in the
processing chain?
Therefore a _default_ +ChangePropagationPolicy+ can be applied on a +MutableConfiguration+ instance, which allows to
control this aspect:
[source,java]
.Explicitly passing the backing configuration
--------------------------------------------
public interface ChangePropagationPolicy {
/**
* Method being called when a multiple key/value pairs are added or updated.
* @param propertySources all property sources, including read-only property sources, of the current configuration,
* never null.
* @param configChange the configuration change, not null.
*/
void applyChange(ConfigChangeRequest configChange, Collection<PropertySource> propertySources);
}
--------------------------------------------
By default, changes are applied to all registered +MutablePropertySource+ instances
similarly.
The +MutableConfigurationProvider+ singleton also provides the most common
change propagation policy implementations:
[source, java]
---------------------------------------------
public final class MutableConfigurationProvider {
[...]
public static ChangePropagationPolicy getApplyAllChangePolicy();
public static ChangePropagationPolicy getApplyMostSignificantOnlyChangePolicy();
public static ChangePropagationPolicy getApplySelectiveChangePolicy(String... propertySourceNames);
public static ChangePropagationPolicy getApplyNonePolicy();
}
---------------------------------------------
==== Some Aspects to consider
Due to Tamaya's design the effective effect of your changes to the overall configuration, cannot
be sometimes a bit tricky to be predicted, since it depends on several aspects:
. is the corresponding configuration resource configured as part of the current system's configuration?
. what is the +PropertySource's+ priority within the configuration context? Is it overriding or overridden
by other sources?
. is the change directly visible to the configuration system? E.g. injected values are normally not updated,
whereas injecting a +DynamicValue<T>+ instance allows to detect and react single value changes. Also the
+PropertySources+ implementation must be able to detect any configuration changes and adapt its values returned
accordingly. Finally values also can be marked as immutable or being cached.
. Is configuration cached, or written/collected directly on access?
. can the changes applied be committed at all?
So it is part of your application configuration design to clearly define, which property sources may be read-only, which
may be mutable, how overriding should work and to which backends finally any changes should be written back.
=== Configuration Changes
This module does not handle detection of changes to the overall system's +Configuration+. This can be done in
several ways, e.g. by:
* using the _tamaya-events_ extension, which can be used to observe the system's configuration and
publishing events when things have been changed.
* The SPI implementing the +MutableConfigurationBackendSpi+ may inform/update any affected +PropertySource,
PropertySourceProvider+ instances about the changes applied.
=== Supported Backends
Multiple backends are supported. E.g. _tamaya-etcd_ also registers
corresponding SPI implementations/backends. This module comes with
the following +MutablePropertySource+ implementations:
* +MutablePropertySource+ resources, targeting local +.properties+ files, using the +java.util.Properties+
format.
* +MutableXmlPropertySource+ resources, targeting local +.xml+ property files, using the +java.util.Properties+
XML format.
=== SPIs
The module defines +MutableConfigurationProviderSpi+, that is used as a delegate by the +MutableConfigurationProvider+
singleton accessor:
[source,java]
.SPI: MutableConfigurationProviderSpi
--------------------------------------------------
public interface MutableConfigurationProviderSpi {
/**
* Creates a new {@link MutableConfiguration} with {@code autoCommit = false} as default.
*
* @param configuration the configuration, not null.
* @param propagationPolicy policy that defines how changes are published to the property
* sources.
* @return a new mutable configuration instance.
*/
MutableConfiguration createMutableConfiguration(Configuration configuration,
ChangePropagationPolicy propagationPolicy);
}
--------------------------------------------------
Implementations are registered with the current +ServiceContext+ (using by default the
+java.util.ServiceLoader+ service).