| :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). |