http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_injection.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_injection.adoc b/content/extensions/mod_injection.adoc new file mode 100644 index 0000000..dc68626 --- /dev/null +++ b/content/extensions/mod_injection.adoc @@ -0,0 +1,445 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Injection +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Core]] +== Tamaya Injection (Extension Module) +=== Overview + +Tamaya Injection is an extension module. Refer to the link:modules.html[extensions documentation] for further details +about modules. + +Tamaya Injection provides functionality for injecting configured values into beans, or creating configuration +template instances. + +Inversion of Control (aka IoC/the Hollywood Principle) has proven to be very useful and effective in avoiding boilerplate +code. In Java there are different frameworks available that all provide IoC mechanisms. Unfortunately IoC is not a +built-in language feature. So for a portable solution that works also in Java SE Tamaya itself has to provide the +according injection services. This module adds this functionality to Tamaya. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +Basically Tamaya's injection API is deployed as API artifact: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection-api</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +To use injection with Java SE you must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-injection</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +Similarly there are other injection implementations available, targetig platforms such as + +* Spring, Spring Boot +* Java EE/CDI +* OSGI, Apache Felix/Apache Karaf + + +=== Core Concepts + +Basically you annotate fields or methods in your beans with +@Config+ to enable configuration injection. Tamaya +additionally defines further annotations that allo you to define additional aspects such as default values, custom +converters etc. The following example illustrates the basic functionality: +code snippet: + +[source,java] +.Annotated Example Class +-------------------------------------------- +package foo.bar; + +public class ConfiguredClass{ + + // resolved by default, using property name, class and package name: foo.bar.ConfiguredClass.testProperty + private String testProperty; + + // Trying to resolve mutiple keys, with a default value, if none could be resolved + @Config({"a.b.c.key1","a.b.legacyKey",area1.key2"}, defaultValue="The current \\${JAVA_HOME} env property is ${env:JAVA_HOME}.") + String value1; + + // Typical case + @Config("a.b.c.key2") + private int value2; + + // resolved by default as foo.bar.ConfiguredClass.accessUrl + // Using a (default) String -> URL converter + @Config(defaultValue="http://127.0.0.1:8080/res/api/v1/info.json") + private URL accessUrl; + + // Config injection disabled for this property + @NoConfig + private Integer int1; + + // Overriding the String -> BigDecimal converter with a custom implementation. + @Config("BD") + @WithPropertyConverter(MyBigDecimalRoundingAdapter.class) + private BigDecimal bigNumber; + + ... +} +-------------------------------------------- + + +When configuring data or configuration classes it is also possible to auto-inject the fields identified. For activating +this feature a class must be annotated with +@ConfigAutoInject+: + +[source, java] +. An autoinjected bean class +-------------------------------------------- +package a.b; + +@ConfigAutoInject +public final class Tenant{ + private int id; + private String name; + private String description; + @NoConfig // prevents auto injection for this field + private String id2; + + public int getId(){ + return id; + } + public String getName(){ + return name; + } + public String getDescription(){ + return description; + } +} +-------------------------------------------- + +These examples do not show all possibilities provided. Configuring instance of these +class using Tamaya is very simple: Just pass the instance to Tamaya to let +Tamaya inject the configuration (or throw a +ConfigException+, if this is not possible): + +[source,java] +.Configuring the +ConfiguredClass+ Instance +-------------------------------------------- +ConfiguredClass classInstance = new ConfiguredClass(); +ConfigurationInjector.configure(configuredClass); + +Tenant tenant = new Tenant(); +ConfigurationInjector.configure(tenant); +-------------------------------------------- + +NOTE: Configuration injection works similarly, when used with other integration modules, e.g. when Tamaya is used +with CDI, Spring or within an OSGI container. For further details refer also to the corresponding integration module's +documentation. + + +=== The Annotations in detail +==== The ConfigurationInjector + +The +ConfigurationInjector+ interface provides methods that allow any kind of instances to be configured +by passing the instances to +T ConfigurationInjector.getInstance().configure(T);+. The classes passed +hereby must not be annotated with +@Config+ for being configurable. By default Tamaya +tries to determine configuration for each property of an instance passed, using the following resolution policy: + +Given a class +a.b.MyClass+ and a field +myField+ it would try to look up the following keys: +[source, listing] +-------------------------------------------- +a.b.MyClass.myField +a.b.MyClass.my-field +MyClass.myField +MyClass.my-field +myField +my-field +-------------------------------------------- + +So given the following properties: + +[source, properties] +-------------------------------------------- +a.b.Tenant.id=1234 +Tenant.description=Any kind of tenant. +name=<unnamed> +-------------------------------------------- + + +==== Accessing ConfiguredItemSupplier instances + +In many cases you want to create a supplier that simply creates instances that are correctly configured as defined +by the current context. This can be done using +Suppliers+: + +[source, java] +-------------------------------------------- +ConfiguredItemSupplier<Tenant> configuredTenantSupplier = ConfigurationInjector.getInstance().getConfiguredSupplier( + new ConfiguredItemSupplier<Tenant>(){ + public Tenant get(){ + return new Tenant(); + } +}); +-------------------------------------------- + +With Java 8 it's even more simpler: + +[source, java] +-------------------------------------------- +ConfiguredItemSupplier<Tenant> configuredTenantSupplier = ConfigurationInjector.getInstance().getConfiguredSupplier( + Tenant::new); +-------------------------------------------- + +Hereby this annotation can be used in multiple ways and combined with other annotations such as +@DefaultValue+, ++@WithLoadPolicy+, +@WithConfigOperator+, +@WithPropertyConverter+. + +==== Minimal Example + +To illustrate the mechanism below the most simple variant of a configured class is given: + +[source,java] +.Most simple configured class +-------------------------------------------- +pubic class ConfiguredItem{ + @Config + private String aValue; +} +-------------------------------------------- + +When this class is configured, e.g. by passing it to +ConfigurationInjector.getInstance().configure(Object)+, +the following is happening: + +* The current valid +Configuration+ is evaluated by calling +Configuration cfg = ConfigurationProvider.getConfiguration();+ +* The current property value (String) is evaluated by calling +cfg.get("aValue");+ for each possible key (mutliple + keys are possible). +* if not successful, an error is thrown (+ConfigException+) +* On success, since no type conversion is involved, the value is injected. + +==== Using @DefaultValue + +In the next example we explicitly define the property value: +[source,java] +-------------------------------------------- +pubic class ConfiguredItem{ + + @Config({"aValue", "a.b.value","a.b.deprecated.value"}, defaultValue="${env:java.version}") + private String aValue; +} +-------------------------------------------- + +==== Inject a DynamicValue Property + +Within this example we evaluate a dynamic value. This mechanism allows you to listen for configuration changes and to +commit new values exactly, when convenient for you. + +[source,java] +-------------------------------------------- +pubic class ConfiguredItem{ + + @Config({"aValue", "a.b.value","a.b.deprecated.value"}, defaultValue="${env:java.version}") + private DynamicValue aValue; +} +-------------------------------------------- + +The +DynamicValue+ provides you the following functionality: + +[source,java] +-------------------------------------------- +public interface DynamicValue<T> { + + enum UpdatePolicy{ + IMMEDIATE, + EXPLCIT, + NEVER, + LOG_AND_DISCARD + } + + T get(); + T getNewValue(); + T evaluateValue(); + T commitAndGet(); + void commit(); + void discard(); + boolean updateValue(); + + void setUpdatePolicy(UpdatePolicy updatePolicy); + UpdatePolicy getUpdatePolicy(); + void addListener(PropertyChangeListener l); + void removeListener(PropertyChangeListener l); + + boolean isPresent(); + T orElse(T other); + T orElseGet(ConfiguredItemSupplier<? extends T> other); + <X extends Throwable> T orElseThrow(ConfiguredItemSupplier<? extends X> exceptionSupplier) throws X; + +} +-------------------------------------------- + +Summarizing this class looks somehow similar to the new +Optional+ class added with Java 8. It provides +a wrapper class around a configured instance. Additionally this class provides functionality that gives +active control, to manage a configured value based on a ++LoadingPolicy+: + +* +IMMEDEATE+ means that when the configuration system detects a change on the underlying value, the new value + is automatically applied without any further notice. +* +EXPLICIT+ means that a new configuration value is signalled by setting the +newValue+ property. if +getNewValue()+ + returns a non null value, the new value can be applied by calling +commit()+. You can always access the newest value, + hereby implicitly applying it, by accessing it via +commitAndGet()+. Also it is possible ti ignore a change by calling + +discard()+. +* +NEVER+ means the configured value is evaluated once and never updated. All changes are silently discarded. +* +LOG_AND_DISCARD+ similar to +NEVER+, but changes are logged before they are discarded. + +Summarizing a +DynamicValue+ allows you + +* to reload actively updates of configured values. +* update implicitly or explicitly all changes on the value. +* add listeners that observe changes of a certain value. + +Dynamic values also allow on-the-fly reevaluation of the value by calling +evaluateValue()+. Hereby the value of the +instance is not changed. + + +==== Ommitting Injection using @NoConfig + +Adding the @NoConfig annotation prevents a field or method to be auto-injected from +configuration. This is especially useful, if a type is annotated as @ConfigAutoInject with auto-confiuration +turned on as follows: + +[source,java] +-------------------------------------------- +@ConfigAutoInject +pubic class ConfiguredItem{ + + @NoConfig + private transient int sum; + + private String a; + private String b; + Private String c; +} +-------------------------------------------- + +In this case the fields +a,b,c+ are configured, whereas the field +sum+ is ignored regarding +configuration. + +==== Adding custom operators using @WithConfigOperator + +The @WithConfigOperator annotation allows you define a class of type +ConfigOperator+, to being applied +to the final +Configuration+, BEFORE the value is injected. This can be used for various use cases, e.g. +filtering or validating the visible properties for a certain use case. + +[source,java] +-------------------------------------------- + +@WithConfigOperator(MyConfigView.class) +pubic class ConfiguredItem{ + + @Config + private String a; + +} +-------------------------------------------- + + +==== Adding custom property converters using @WithPropertyConverter + +The @WithPropertyConverter annotation allows you to define a class of type +PropertyConverter+, to be applied +on a property configured to convert the String value to the expected injected type. This can be used for +various use cases, e.g. adding custom formats, config models, decryption. + +[source,java] +-------------------------------------------- + +pubic class ConfiguredItem{ + + @WithPropertyConverter(MyPropertyConverter.class) + @Config + private String a; + +} +-------------------------------------------- + + +==== Defining the loading policy to be applied to configured values using @WithLoadPolicy + +The @WithLoadPolicy annotation allows to define the loading behaviour to be applied. The +LoadPolicy+ +enum hereby defines the various loading modes. + +[source,java] +-------------------------------------------- + +@WithLoadPolicy(LoadPolicy.NEVER) +pubic class BootTimeStableConfig{ + + @WithPropertyConverter(MyPropertyConverter.class) + @Config + private String a; + +} +-------------------------------------------- + + +=== Configuration Events + +Similar to CDI Tamaya publishes Configuration events, when instances were configured. It depends on the effective +event backend in use, if and how events are published: + +* when you have the CDI extension active events are published using the default CDI event mechanism. +* in all other scenarios events are delegated to the +tamaya-events+ module, if available, +* if no event delegation is available no events are published. + +The event published is very simple: + +[source,java] +-------------------------------------------- +public interface ConfiguredType { + Class getType(); + String getName(); + public Collection<ConfiguredField> getConfiguredFields(); + Collection<ConfiguredMethod> getConfiguredMethods(); + void configure(Object instance, Configuration config); +} + + +public interface ConfiguredField { + Class<?> getType(); + Collection<String> getConfiguredKeys(); + String getName(); + String getSignature(); + Field getAnnotatedField(); + void configure(Object instance, Configuration config); +} + +public interface ConfiguredMethod { + Collection<String> getConfiguredKeys(); + Class<?>[] getParameterTypes(); + Method getAnnotatedMethod(); + String getName(); + String getSignature(); + void configure(Object instance, Configuration config); +} +----------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_jodatime.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_jodatime.adoc b/content/extensions/mod_jodatime.adoc new file mode 100644 index 0000000..e806af6 --- /dev/null +++ b/content/extensions/mod_jodatime.adoc @@ -0,0 +1,64 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: JodaTime +:jbake-type: page +:jbake-status: published + +toc::[] + +[[Core]] +== Tamaya JodaTime (Extension Module) + +=== Overview + +Tamaya JodaTime is an extension module to support the usage of http://www.joda.org/joda-time/[Joda-Time] +in conjunction with Tamaya. Tamaya JodaTime defines some additional property +converters to retrieve Joda-Time types from a given configuration. + +Refer to the link:modules.html[extensions documentation] for further details +about modules. + +tools to locate resources in your classpath or file system based on descriptive +ant-styled resource patterns. To use this module add the following dependency: + +[source, listing] +----------------------------------------------- +<dependency> + <grooupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-jodatime</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +After adding this dependency to your project you can retrieve +Joda-Time based values directly from a given configuration. + +[source,java] +----------------------------------------------- +Configuration configuration = ConfigurationProvider.getConfiguration(); + +DateTime pit = configuration.get("pointInTime", DateTime.class) +----------------------------------------------- + +=== Specifying date and time values + +To be written. + +=== Specifing periods and durations + +To be written. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_json.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_json.adoc b/content/extensions/mod_json.adoc new file mode 100644 index 0000000..77c5b7d --- /dev/null +++ b/content/extensions/mod_json.adoc @@ -0,0 +1,77 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Builder +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[BuilderCore]] +== Tamaya JSON (Extension Module) +=== Overview + +The Tamaya json module provides support for reading configuration using the JSON format: + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-json</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== Reading configuration in JSON + +For reading JSON based onfiguration most easily a +JSONFormat+ can be provided: + +[source, java] +----------------------------------------------- +ConfigurationData dataRead = ConfigurationFormats.readConfig( + getClassLoader().getResource("myFileConfig.json"), new JSONFormat())); +----------------------------------------------- + +=== Examples + +The JSON module adds instances of +ConfigurationFormat+ so JSON configuration can be read and mapped to the +according property maps. E.g. the following file is a simple and correct JSON configuration: + +[source,listing] +---------------------------------------------------------------- +{ + "a" : "A", + "b" : "B", + "c" : "C", + "d" : { + "o" : "O", + "p" : "P" + } +} +---------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_management.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_management.adoc b/content/extensions/mod_management.adoc new file mode 100644 index 0000000..f8050ec --- /dev/null +++ b/content/extensions/mod_management.adoc @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: JMX Management Access +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[ExtModel]] +== Tamaya Management (JMX Support) (Extension Module) +=== Overview + +The Tamaya management module provides support for registering a JMX management bean for accessing configuration. + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-management</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== The ManagedConfigMBean bean + +The management model defines the MBean of type +ManagedConfigMBean+ as follows: + + +[source,java] +----------------------------------------------------------------------------- +public interface ManagedConfigMBean { + String getJsonConfigurationInfo(); + String getXmlConfigurationInfo(); + Map<String, String> getConfiguration(); + Map<String, String> getSection(String area, boolean recursive); + Set<String> getSections(); + Set<String> getTransitiveSections(); + boolean isSectionExisting(String area); + default boolean isSectionEmpty(String area); +} +----------------------------------------------------------------------------- + +* +getJsonConfigurationInfo,getXmlConfigurationInfo+ return a JSON or XML representation of the +current configuration. +* +getConfiguration+ access the current configuration properties. +* +getSection+ allows to extract all entries below a certain subkey. With _recursive_ the query + will not only return direct children, but also recursively walk down all subsection of the + given section key. +* +getSections+ returns all current known section names. +* +getTransitiveSections+ return all sections, but also adds all transitive subsection as single + entries to the set as well. +* +isSectionExisting+ and +isSectionEmpty+ allow for quering if entries are present under the given + section keys. + +=== Registering the ManagedConfigMBean + +For registering the current +ManagedConfigMBean+ instance to the current MBean platform server, the +following static methods are available: + +[source,java] +----------------------------------------------------------------------------- +public final class ConfigManagementSupport{ + + private JMXSupport(){} + + public static ObjectName registerMBean(); + public static ObjectName registerMBean(String context); + public static ObjectName unregisterMBean(); + public static ObjectName unregisterMBean(String context); +} +----------------------------------------------------------------------------- + +* +registerMBean+ creates a new +ManagedConfigMBean+ instance using the +ServiceContextManager+ + and registers it. Optionally an additional _context_ parameter can be passed, which allows + to register the management bean for different classloaders, e.g. for different + ears. +* +unregisterMBean+ does the oppsite than registering obviously. + +NOTE: The instance of +ManagedConfigMBean+ to be created and registered is evaluated by use og the + +ServiceContextManager+. So you can replace the bean implementation by registering your + overriding implementation using the current +ServiceContext+ (by default using + +java.util.ServiceLoader+ and +@Priority+ annotation. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_metamodel-staged.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_metamodel-staged.adoc b/content/extensions/mod_metamodel-staged.adoc new file mode 100644 index 0000000..7482d1a --- /dev/null +++ b/content/extensions/mod_metamodel-staged.adoc @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Staged PropertySources +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Remote]] +== Tamaya Metamodel: Staged PropertySources (Extension Module) +=== Overview + +The Tamaya Staged PropertySources extension provides a base class and default implementation for loading +multistaged configuration easily from a common configuration location. + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from Tamaya CDI integration you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext.metamodels</groupId> + <artifactId>tamaya-metamodel.staged</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +The component will not register any components. The component basically provides the following options: + +* Use it as default configuration extension. Hereby you should define your stages in use by setting the + +env.STAGE+ system property with the stages to be loaded in order of precedence (most significant last), + e.g. +sys-env,DEFAULTS,TEST,DEVELOPMENT. _Additionally_ you must register + +org.apache.tamaya.staged.StagedConfigPropertiesProvider+ as in + +-------------------------------------------------------------- +META-INF +|_service + |_org.apache.tamaya.spi.PropertySourceProvider +-------------------------------------------------------------- + +Tamaya will then load .properties files from +System.getenv(), +classpath:DEFAULTS.properties, classpath:TEST.properties+ and ++classpath:DEVELOPMENT.properties+ + +* For more advanced requirements, such as alternate locations, patterns or formats, you can also extend one of the + provided classes (+org.apache.tamaya.staged.StagedConfigPropertiesProvider+, + ** +BaseStagedPropertySourceProvider+). Extending provides features such as: + + ** Defining a prefix for all entries provided/loaded. + ** Using alternate locations or formats. + ** Defining the ordinals used. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_model.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_model.adoc b/content/extensions/mod_model.adoc new file mode 100644 index 0000000..2b05026 --- /dev/null +++ b/content/extensions/mod_model.adoc @@ -0,0 +1,467 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Model Documentation and Validation +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[ExtModel]] +== Tamaya Model Documentation and Validation (Extension Module) +=== Overview + +The Tamaya model module provides support for documenting configuration and validating configuration read and processed +against this model. Documentation and config models can be provided in different ways: + +* as separate meta-model documents +* by providers that check classes/packages for configuration annotations (planned) + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-model</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== Describing the Configuration Meta-Model + +Basically configuration is modelled using key, value-pairs. Looking at a keys ++a.b.c.param1+ and +a.b.c.param2+ the following concepts can be used to defined/describe +configuration: + +. the _configuration section:_ In our case this equals to +a.b.c+, which itself also includes the + transitive entries +a.b+ and +a+. +. the _configuration parameter:_ Basically parameters are adressed using their fully qualified names, + which equals to the containing section name and the relative parameter name, separated by the dor separator. + In the above example +a.b.c.param1+ and +a.b.c.param2+ are the fully qualified parameter names. + +Now with only these 2 concepts a simple configuration meta-model can be defined as + +* a meta-model's name, used just for grouping different meta-models and entries to better separate + descriptions, e.g. in a management console or generated configuration documentation site. +* a set of sections. +* a set of parameters. +* Both, sections (+.model.target=Section+) as well as parameter models (+.model.target=Parameter+) + ** can be modelled by a meta-data entry, by default +_my.config.key.model+. + ** may be required, or optional (+.model.required=true|false+) + ** may have an optional description +* Parameters additionally have + ** a _type_ (+.model.type=Classname+), described by the fully qualified class name, into which any configured (String) + value must be convertable into. If no type is configured +java.ui.lang.String+ is assumed as default. + ** an optional regular expression that can be used to validate the +String+ values returned from a + configuration (+.model.expression=regexpression+). + +Given these concepts a configuration can be fully described. Entries that are not contained in one of the given +sections (or its children), or parameters not described or marked as valid (e.g. for dynamic configModels of +a section), are called _undefined_. Undefined parameters should be grouped with its parent section. Each section, as +well as all parent sections, including transitive) of any parametet read, should similarly marked as undefined, if and +only if + +. the section itself is (directly) _undefined_ +. the section is not a _super section_ of a defined section. + +As en example the section definition of +a.b.c+ also implicitly includes the sections +a.b+ and +a+ to be defined +sections, despite the fact that section properties, such as description and custom configModels are not inherited to +its parent, or child section. + + +=== Defining Meta-Configuration Model + +The configuration meta-model is defined by simple configuration meta-data entries. The section for all model +configuration by default is called +model+, which results in entries such as +_my.config.key.model.target=Section+. +Within this section fully qualified configuration keys defines +which part of the configuration is targeted by certain entries. + +==== Defining Sections + +First we start to define some configuration sections, the example below starts with the most important +variants supported: + +[source,listing] +------------------------------------------------------------------------------- +# Metamodel information +_model.provider=ConfigModel Extension + +# org.mycompany.root (optional section) +_org.mycompany.root.model.target=Section +_org.mycompany.root.model.description=Root section defining my company configuration. + +# org.mycompany.security (required section) +_org.mycompany.security.model.target=Section +_org.mycompany.security.model.required=true +_org.mycompany.security.model.description=Security related settings.\ + refer for further details to XXX. + +# minmal section +_minimal.model.target=Section + +# custom validated section +_validated.model.target=Section +_validated.model.validator=org.apache.tamaya.model.TestValidator +------------------------------------------------------------------------------- + +Above +org.mycompany.root+ transitively defines 3 sections: + +* org +* org.mycompany +* org.mycompany.root + +All sections are optional. Additionally the model above also defines a required section +org.mycompany.security+. +Required sections are checked so the section is not empty. It is not checked for any specific parameter hereby, +only the existance of any child parameter is validated. + +The _class_ attribute has to be defined for any section definition, because if not set a model entry is, by default, +defined to be a parameter configModel entry. Given above the entry for the section +minimal+ shows such a minimal +entry. + ++validated+ defines a section, which is validated through a customizable validator. Hereby an ordered list of validators +can be provided, separated by commas. + + +==== Defining Parameters + +Similarly parameters also can be defined: + +[source,listing] +------------------------------------------------------------------------------- +# org.mycompany.root.name (required parameter) +_org.mycompany.root.name.model.target=Parameter +_org.mycompany.root.name.model.required=true +_org.mycompany.root.name.model.description=The company's name, also used in the application's main header. + +# org.mycompany.security (required parameters) +_org.mycompany.security.uid.model.required=true +_org.mycompany.security.uid.model.description=The user id. +_org.mycompany.security.realm.model.required=true +_org.mycompany.security.realm.model.validator=org.apache.tamaya.model.RealmValidator +_org.mycompany.security.realm.model.description=The security realm required. +_org.mycompany.security.tokenid.model.description=The token id, if the token service is used (optional). + +# A minmal parameter +_minimalClass.model.target=Class +------------------------------------------------------------------------------- + +Similarly as when defining section also parameter entries define transitively its containing sections. E.g. +the entry above for +org.mycompany.security.realm+ also defines the following sections (as optional). + +* org +* org.mycompany +* org.mycompany.security + +Additional entries for section, e.g. configModels to be done, can be added as described in the previous section, +but are optional. + +Since the parameter is the default type for model entries, a minmal parameter model entry only only needs it's +parameter type to be defined. In the example above we define a parameter +minimalClass+ of type +Class+. +Types hereby are fully qualified class names, whereas as 'java.ui.lang' for built-in language types can be +ommitted. + +==== Model Locations + +By default the configuration model can be defined at the following locations: + +* +classpath*:META-INF/configmodel.properties+, separate to the current +Configuration+. This functionality is enabled + by default, but can be disabled by adding +org.apache.tamaya.model.default.enabled=false+ to your current + +Configuration+. +* +implicitly as part of the current +Configuration+. THis can be disabled by setting + the +org.apache.tamaya.model.integrated.enabled+ configuration poarameter to +false+. +* customized by configuring the +org.apache.tamaya.model.resources+ in the current +Configuration+. This + parameter allows to define the locations from where the model extension is trying to read the + model configuration. If the _resources extension_ is available in your system it is used to + evaluate the locations. If not the default +Classloader.getResources+ command is issued. Also it + is required that the _formats extension_ is available, since this is used to effectively read the + data. This extension also allows you to use alternate representation formats such as +ini, xml, yml, json+. + + +=== Tracking Configuration Access + +The model module also allows tracking which code accesses configuration properties or configuration parameters. +It checks the stacktrace to evaluate the calling code location, hereby any unwanted packages can be implicitly +ommitted from the stacktrace. Also the maximal length of the stacktrace retained can be constraint in length. +The usages are recorded as +Usage+ instances. Hereby for each parameter accessed a corresponding +Usage+ +instance is created. It can be accessed by calling +Usage ConfigUsageStats.getUsage(String key)+. Usage +statistics for calling +Configuration.getProperties()+ can be obtained calling +Usage getUsageAllProps();+. + +Usage tracking is disabled by default. It can be enabled by calling +ConfigUsageStats.enableUsageTracking(true);+. ++ConfigUsageStats.isUsageTrackingEnabled()+ returns the current tracking status. + +The +Usage+ class itself provides access to further fainer grained usage data (+AccessDetail+) containing: + +* the access point (+fqn.ClassName#method(line: xxx)+). +* the number of accesses +* the first an last access +* the values read +* the access stacktrace (filtered by ignored packages). + +[source,java] +----------------------------------------------------------- +public final class Usage { + [...] + public String getKey(); + public void clearMetrics(); + public int getReferenceCount(); + public int getUsageCount(); + public Collection<AccessDetail> getAccessDetails(Class type); + public Collection<AccessDetail> getAccessDetails(Package pack); + public Collection<AccessDetail> getAccessDetails(String lookupExpression); + public Collection<AccessDetail> getAccessDetails(); + public void trackUsage(String value); + public void trackUsage(String value, int maxTraceLength); + + + public static final class AccessDetail { + [...] + public void clearStats(); + public long trackAccess(String value); + public long getAccessCount(); + public String getAccessPoint(); + public long getFirstAccessTS(); + public long getLastAccessTS(); + public String[] getStackTrace(); + public Map<Long, String> getTrackedValues(); + } + +} +----------------------------------------------------------- + +With +ConfigUsageStats.clearUsageStats()+ the collected statistics can be reset at any time. Summarizing the main +singleton for configuration statistics is defined as follows: + +[source,java] +----------------------------------------------------------- +public final class ConfigUsageStats{ + public static Set<String> getIgnoredUsagePackages(); + public static void addIgnoredUsagePackages(String... packageName); + public static void enableUsageTracking(boolean enabled); + public static Usage getUsage(String key); + public static Collection<Usage> getUsages(); + public static void clearUsageStats(); + public static Usage getUsageAllProperties(); + public static boolean isUsageTrackingEnabled(); + public static String getUsageInfo(); +} +----------------------------------------------------------- + +==== Customizing the Stacktrage for Usage Reporting + +The stacktrace tracked by the system can be customized in several ways: + +* +ConfigUsageStats.addIgnoredPackageNames(String...)+ allows to add additional ignored package names. +* With +Usage.setMaxTraceLength(int)+ the maximal size of the stacktraces logged can be set. Setting a + negative value will disable stacktrace logging completelely. + + +=== Accessing Usage Statistics + +Bascially usage statistics are available in two forms: + +* The +Usage/AccessDetail+ object tree can be accessed programmatically from the +ConfigUsageStats+ + singleton. +* With +ConfigUsageStats.getUsageInfo()+ also a textual representation of the usage statistics + can be obtained, as illustrated below (a snipped from the current test output): + +[source,listing] +----------------------------------------------------------- +Apache Tamaya Configuration Usage Metrics +========================================= +DATE: Sat Apr 30 21:51:09 CEST 2016 + +220 <<all>>: + - 220 <unknown/filtered/internal> , first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 +3 java.version: + - 2 test.model.TestConfigAccessor#readProperty(line:43), first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 + - 1 <unknown/filtered/internal> , first=Sat Apr 30 21:51:09 CEST 2016, last=Sat Apr 30 21:51:09 CEST 2016 + +----------------------------------------------------------- + + +==== Programmatic API + +Basically the configModel module provides a simple API to access the defined +ConfigModel+ instances and +validating the current +Configuration+ against the models as follows: + +[source,java] +----------------------------------------------------------- +public final class ConfigModelManager { + + private ConfigModelManager() {} + + public static Collection<ConfigModel> getModels(); + public static Collection<ConfigModel> findModels(ModelType type, String namePattern); + public static <T extends ConfigModel> T getModel(String name, Class<T> modelType); + public static Collection<ConfigModel> findModels(String namePattern); + + public static Collection<ValidationResult> validate(); + public static Collection<ValidationResult> validate(boolean showUndefined); + public static Collection<ValidationResult> validate(Configuration config); + public static Collection<ValidationResult> validate(Configuration config, boolean showUndefined); + + public static void registerMBean(); + public static void registerMBean(String context); + +} +----------------------------------------------------------- + +This singleton allows to validate the current or any +Configuration+ instance. All the ConfigModels read also are +available from the +getModels+ method. This models can be used to provide documentation, e.g. as part of a CLI interface +or shown on a documentation web server. + +A +ConfigModel+ hereby is defined as one single part of configuration, typically corresponding to a specific concern +of your system. As an example you can define different models for different modules or products plugged together. +With resolution mechanism in place you can also define a shared module that is targeted by multiple modules as a +single configuration source (e.g. for configuring the machine's IP address and subnet settings only once. + +[source,java] +----------------------------------------------------------- +public interface ConfigModel { + + ModelTarget getType(); + String getName(); + String getProvider(); + boolean isRequired(); + String getDescription(); + Collection<ValidationResult> validate(Configuration config); +} +----------------------------------------------------------- + + +Hereby +ModelTarget+ defines more details on the kind of model: + +[source,java] +----------------------------------------------------------- +public enum ModelTarget { + /** + * A configuration section. + */ + Section, + /** + * A configuration paramter. + */ + Parameter, + /** + * ConfigModel that is a container of other validations. + */ + Group +} +----------------------------------------------------------- + +A +ValidationResult+ models one validation executed by a +ConfigModel+ on a certain +Configuration+ instance: + +[source,java] +----------------------------------------------------------- +public final class ValidationResult { + + public static ValidationResult ofValid(ConfigModel configModel); + public static ValidationResult ofMissing(ConfigModel configModel); + public static ValidationResult ofMissing(ConfigModel configModel, String message); + public static ValidationResult ofError(ConfigModel configModel, String error); + public static ValidationResult ofWarning(ConfigModel configModel, String warning); + public static ValidationResult ofDeprecated(ConfigModel configModel, String alternateUsage); + public static ValidationResult ofDeprecated(ConfigModel configModel); + public static ValidationResult ofUndefined(final String key); + public static ValidationResult of(ConfigModel configModel, ValidationState result, String message); + + public ConfigModel getConfigModel(); + public ValidationState getResult(); + public String getMessage(), +} +----------------------------------------------------------- + +The result of a complete validation on a concrete +Configuration+ instance finally is mapped as a ++Collection<ValidationResult>+, refer to the methods on +ConfigModelManager+. + + +=== Auto-Documentation of Classes with Configuration Injection + +A special feature of this module is that it observes +ConfigEvent+ published through Tamaya'as event channel +(+tamaya-events+ module). If no metaconfiguration model is found the model manager by default automatically creates +models for all injected instances on the fly. In the case of CDI integration this happens typically during deployment +time, since CDI initializes during deployment time. Other runtime platforms, such as OSGI, may have rather different +behaviour. Nevertheless this means that after your system has been started you should have access to a complete +set of +ConfigModel+ instances that automatically document all the classes in your system that consume configuration +(through injection). + + +== Model SPI +=== Registering Configuration Models + +The model extension also provides an SPI where customized functionality can be added. The main abstraction hereby is +the +ModelProviderSpi+ interface, which allows any kind of additional config models to be added to the system: + +[source,java] +----------------------------------------------------------- +public interface ModelProviderSpi { + + Collection<ConfigModel> getConfigModels(); + +} +----------------------------------------------------------- + +New instances implementing this interface must be registered into the current +ServiceContext+, by default the ++ServiceLoader+ is used. + + +=== The ConfigUsageStatsSpi + +The methods for managing and tracking of configuration changes are similarly delegated to an +implementation of the +org.apache.tamaya.model.spi.ConfigUsageStatsSpi+ SPI. +By implementing this SPI and registerting it with the +ServiceContext+ the usage tracking +logic can be adapted or replaced. + +=== Other Utility Classes + +The module also provides further utility classes that may be useful for implementing models or testing: + +* +AbstractModel+ provides a base class that can be extended, when implementing +ConfigModel+. +* +AreaConfigModel+ provides a +ConfigModel+ implementation (with a corresponding +Builder+) to model the + requirement of certain configuration sections being present, or opionally present, in the model. +* +ParameterModel+ provides an implementation base class for validating parameters on existence and compliance + with a regular expression. +* +ConfigDocumentationMBean+ is the MBean registered that models similar functionality as +ConfigModelManager+. +* +ConfigModelGroup+ provides a +ConfigModel+ that groups several child models. +* +ConfigModelReader+ allows to read +ConfigModels+ from properties files as described at the beginning of this + document. + + +=== Switches to enable/disable functionality + +The model module provides different switches that can be used to activate or deactivate features: + +* +tamaya.model.integrated.enabled+ allows to deactivate reading inline metaconfiguration delivered with + the normal Tamaya Configuration. By default inline entries (+_.abcd.model.*+) are evaluated. +* +tamaya.model.default.enabled+ allows to deactivate reading metamodel information from + +classpath:META-INF/configmodel.properties+. By default it is active. +* +tamaya.model.resources+ allows to define additional resources (loaded through the resources extension), + that can be used to read metamodel information in any format using Tamaya's format module. +* the system property +tamaya.model.autoModelEvents+ allows to activate/deactivate the automatic + documentation of classes configured and published by Tamaya +ConfiguredType+ event instances (e.g. published by + Tamaya's injection modules). http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_mutable_config.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_mutable_config.adoc b/content/extensions/mod_mutable_config.adoc new file mode 100644 index 0000000..2c15e9b --- /dev/null +++ b/content/extensions/mod_mutable_config.adoc @@ -0,0 +1,258 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Mutable Configuration +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Core]] +== Tamaya Mutable Configuration (Extension Module) +=== Overview + +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 some backend systems or the local file system. This module adds this +functionality. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +To benefit from configuration mutability support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-mutable-config</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + +=== Core Architecture + +The core of the module is the +MutableConfigurationProvider+ singleton, which provides access to +MutableConfiguration+ +instance, which extends +Configuration+. This interface adds additional methods to add/update or remove property values. +Hereby changes applied are managed in a transaction like context, called +ConfigChangeContext+. Each context defines +a UUID that identifes a change. +Backends for writing changes applied are of type +MutablePropertySource+, similarly extending the +PropertySource+ +SPI with methods for writing changes back. Registrations and ordering policies are like with ordinary property sources, +with one important difference. Mutable property source can be targeted by write operations. + +Summarizing a +MutableConfiguration+ can be obtained as follows: + +[source,java] +.Accessing and changing a configuration +-------------------------------------------- +MutableConfiguration config = MutableConfigurationProvider.createMutableConfiguration(); +config.set("newKey", "newValue") + .set("anotherKey", "updatedValue") + .remove("valueNotValid") + .commit(); +-------------------------------------------- + +In the above scenario we use the overall system's 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 = + MutableConfigurationProvider.createMutableConfiguration(config); +-------------------------------------------- + +NOTE: If a configuration does not contain any +MutablePropertySource+ instances, a +MutableConfiguration+ built + from it will not be able to accept any changes. + + +Following is the complete listing of the +MutableConfigurationProvider+ accessor: + +[source, java] +--------------------------------------------- +public final class MutableConfigurationProvider { + + private MutableConfigurationProvider(){} + + public static MutableConfiguration getMutableConfiguration(); + public static MutableConfiguration getMutableConfiguration(Configuration configuration); + + [...] +} +--------------------------------------------- + +Hereby +MutableConfiguration+ is defined as follows: + +[source, java] +--------------------------------------------- +public interface MutableConfiguration extends Configuration { + + UUID startTransaction(); + void commitTransaction(); + void rollbackTransaction(); + UUID getTransactionId(); + boolean getAutoCommit(); + void setAutoCommit(boolean autoCommit); + + void setChangePropagationPolicy(ChangePropagationPolicy changePropagationPolicy); + ChangePropagationPolicy getChangePropagationPolicy(); + + boolean isWritable(String keyExpression); + boolean isRemovable(String keyExpression); + boolean isExisting(String keyExpression); + List<MutablePropertySource> getMutablePropertySources(); + List<MutablePropertySource> getPropertySourcesThatCanWrite(String keyExpression); + List<MutablePropertySource> getPropertySourcesThatCanRemove(String keyExpression); + List<MutablePropertySource> getPropertySourcesThatKnow(String keyExpression); + + MutableConfiguration put(String key, String value); + MutableConfiguration putAll(Map<String, String> properties); + MutableConfiguration remove(Collection<String> keys); + MutableConfiguration remove(String... keys); + +} +--------------------------------------------- + + +==== Targeting the right MutablePropertySources + +A +Configuration+ may have multiple +MutablePropertySource+ present. These are members of Tamaya's oredered list of ++PropertySources+ to evaluate the configuration. Nevertheless writing back changes requires additional aspects to +be considered: +* Should changes being written back to all mutable property sources? Or should a key that could be added or removed + on a more significant instance not be written/removed on less significant property source instances? +* Should a change be applied only to a specific mutable property source, regardless its position in the + processing chain? + +Therefore a +ChangePropagationPolicy+ can be set on a +MutableConfiguration+ instance, which allows to control +this aspect: + +[source,java] +.Explicitly passing the backing configuration +-------------------------------------------- +public interface ChangePropagationPolicy { + void applyChanges(Collection<PropertySource> propertySources, UUID transactionID, Map<String,String> changes); + void applyChange(Collection<PropertySource> propertySources, UUID transactionID, String key, String value); + void applyRemove(Collection<PropertySource> propertySources, UUID transactionID, String... keys); + +} +-------------------------------------------- + +By default, changes are applied to all registered +MutablePropertySources+ similarly. + + +Also the +MutableConfigurationProvider+ provides access to the most commonly used change propagation policies: + +[source, java] +--------------------------------------------- +public final class MutableConfigurationProvider { + + private MutableConfigurationProvider(){} + + public static MutableConfiguration getMutableConfiguration(); + public static MutableConfiguration getMutableConfiguration(Configuration configuration); + + 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 easily 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+ ordinal? 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. +. 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. To +support such fine granular scenarios a +MutableConfiguration+ also offers methods to determine if a key +is writable at all or can be removed or updated: + +[source,java] +.Checking for mutability +-------------------------------------------- +MutableConfiguration config = MutableConfigurationProvider.createMutableConfiguration(); + +if(config,isWritable("mycluster.shared.appKey")){ + config.set("newKey", "newValue"); +} +if(config,isRemovable("mycluster.myapp.myKey")){ + config.remove("mycluster.myapp.myKey"); +} +config.commit(); +-------------------------------------------- + + +=== 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. the _etcd_ integration module of Tamaya also registers +corresponding SPI implementations/backends. By default this module comes with +the following +MutablePropertySource+ implementations: + +* +MutablePropertySource+ resources, targeting local .properties files, following the +java.util.Properties+ + format. +* +MutableXmlPropertySource+ resources, targeting local .xml property files, following 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 { + MutableConfiguration createMutableConfiguration(Configuration configuration); +} +-------------------------------------------------- + +Implementations are registered with the current +ServiceContext+, by default as a + +java.util.ServiceLoader+ service. + + +As convenience the following base classes are provided: + +* +org.apache.tamaya.mutableconfig.propertysource.AbstractMutablePropertySource+ simplifying implementation of + +MutablePropertySource+. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_optional.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_optional.adoc b/content/extensions/mod_optional.adoc new file mode 100644 index 0000000..f97e052 --- /dev/null +++ b/content/extensions/mod_optional.adoc @@ -0,0 +1,70 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Optional Tamaya Configuration +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Optional]] +== Tamaya Optional Configuration (Extension Module) +=== Overview + +The Tamaya optional module provides contains three types only. It is for projects that want to benefit from Tamaya +configuration optionally only. E.g. doing an OSS project you can declare to support configuration with Tamaya as +an optional extension. This module can be added as a hard dependency to your code, hereby adding only three artofacts. +It automatically checks the availability of Tamaya on the classpath and only if available tries to access it for +configuration evaluation. Additionally an EvaluationPolicy lets you define the precedence of configured values +(yours, or Tamaya ones if present). + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-optional</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== Reading configuration using the Tamaya Optional Module + +The optional module allows reading configuration with a small subset of functionality only. For extended of full +featured config please consider using the Apache Tamaya as a full configuration backend. + +[source, java] +----------------------------------------------- +BigDecimal interestRate = + OptionalConfiguration.of( + EvaluationPolicy.TAMAYA_OVERRIDES_OTHER, + (k) -> MyConfigMechanism.get(k) // String get(String key); + ) + .get("com.mycomp.ratecalculator.rate", BigDecimal.class)) + .orElse(BigDecimal.of(0.05d)); +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_osgi.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_osgi.adoc b/content/extensions/mod_osgi.adoc new file mode 100644 index 0000000..9a46fd0 --- /dev/null +++ b/content/extensions/mod_osgi.adoc @@ -0,0 +1,132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extensions: OSGI Integrations +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Optional]] +== Tamaya OSGI Support +=== Overview + +Tamaya provides also support for integration with OSGI. Hereby several options are available how Tamaya can be used in +an OSGI context: + +. All Tamaya modules, its API and core library are actually valid OSGI bundles. So adding them into your OSGI modules + and using Tamaya is basically directly supported. Nevertheless OSGI works rather differently from a class- and + resource loading perspective. As long as you rely on Tamaya's mechanisms for resource loading things should work + out of the box. In the back Tamaya's core module actually comes with implicit OSGI support, which is automatically + activated, if Tamaya is running in an OSGI context. This support actually + ** Listens on deployed bundles and actively reads all resources configured as +java.util.ServiceLoader+ services and + registers them as OSGI services. Hereby integration is complete meaning you can also register Tamaya services + as normal OSGI services, e.g. your own +PropertySource+ instances. + ** Uses the OSGI bundle to resolve for resources, because accessing them from the classloader directly + typically fails in an OSGI context. +. Adding Tamaya's OSGI integration module replaces the existing OSGI +ConfigAdmin+ service with an istance based on + Tamaya. Hereby several aspects can be configured using system properties: + ** +org.tamaya.integration.osgi.cm.ranking+ (int) allows to configure the OSGI service ranking used by the Tamaya + BundleActivator to register Tamaya's +ConfigAdmin+ service. In OSGI higher ranking precede lower rankings. By default + Tamaya's OSGI extending service registration mechanism is reusing any annotated +@Priority+ priority values as + corresponsing rankings. + ** +org.tamaya.integration.osgi.cm.override+ (boolean) allows to configure if Tamaya is overriding any existing + values from the default +ConfigAdmin+ instance, or only extending them. In other words this setting allows you to + define, which configuration subsystem has precedence for evaluating the final values, either Tamaya based + configuration (default) or the configuration mechanisms provided by default from your OSGI container (when this flag + is set to +false+). + ** +org.tamaya.integration.osgi.cm.inject+ allows you to deactivate injection of configuration values into your + OSGI services (by default injection is enabled). In all cases accessing the OSGI +ConfigAdmin+ service to + read your configuration is working as usual. But Tamaya adds additional injection functionality, which allows + to inject typed configuration as described by the Tamaya injection api. + +It is also possible to combine things, e.g. when you only define a low ranking for Tamaya's configuration service and +the same time allow injection to be active, you will have Tamaya's injection support based on your default +OSGI configuration. + + +=== Compatibility + +All module described are based on Java 7, so it will run on Java 7 and beyond. +The modules are built against OSGI Compendium version 5.0. + + +=== Installation + +To benefit from Tamaya in an OSGI context you must deploy at least the following modules to your OSGI runtime +environment: + +[source, listing] +----------------------------------------------- +# API and core +org.apache.tamaya:tamaya-api:{tamayaVersion} +org.apache.tamaya:tamaya-core:{tamayaVersion} +org.apache.geronimo.specs:geronimo-annotation_1.2_spec:1.0-alpha-1 +# injection API. SE injection module and dependencies +org.apache.tamaya.ext:tamaya-injection-api:{tamayaVersion} +org.apache.tamaya.ext:tamaya-injection:{tamayaVersion} +org.apache.geronimo.specs:geronimo-atinject_1.0_spec:1.0 +org.apache.geronimo.specs:geronimo-el_2.2_spec:1.0.4 +org.apache.geronimo.specs:geronimo-interceptor_1.1_spec:1.0 +org.apache.geronimo.specs:geronimo-jcdi_1.1_spec:1.0 +# OSGI integration and dependencies +org.apache.tamaya.ext:tamaya-osgi:{tamayaVersion} +org.apache.tamaya.ext:tamaya-functions:{tamayaVersion} +----------------------------------------------- + + +=== Usage + +As an example, what is possible you can implement an OSGI service as a normal POJO and publish it as an OSGI service. +Given that configuration can be injected very easily: + +[source, java] +----------------------------------------------- +public class HelloServiceImpl implements HelloService{ + + @Config("example.message") + @ConfigDefault("A Tamaya default.") + private String message; + + @Override + public String sayHello() { + System.err.println("HELLO: " + message); + return message; + } +} +----------------------------------------------- + + +=== SPI + +By defauklt the OSGI pid or factory pid is mapped to a corresponding root section in Tamaya's configuration. We are +well aware that this might not always be the desired approach. Therefore there as an SPI service provided that allows +to determine this mapping: + +[source, java] +.OSGIConfigRootMapper +----------------------------------------------- +public interface OSGIConfigRootMapper { + + String getTamayaConfigRoot(String pid, String factoryPid); +} +----------------------------------------------- + +Registering your own implementation as an OSGI service allows you to redefine the key mapping. +By default a configuration mapping for +pid/factoryPid==myBundle+ is mapped to +[bundle:myBundle]+. +This mapping is used as a prefix when collecting the corresponding entries for the OSGI configuration. http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_remote.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_remote.adoc b/content/extensions/mod_remote.adoc new file mode 100644 index 0000000..4d947e5 --- /dev/null +++ b/content/extensions/mod_remote.adoc @@ -0,0 +1,131 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Remote Configuration +:jbake-type: page +:jbake-status: published + +toc::[] + + +[[Remote]] +== Tamaya Remote Configuration (Extension Module) +=== Overview + +The Tamaya remote module provides support for reading configuration from remote resources. It provides +especially out-of-the-box support for reading scoped configuration from a configuration server as +provided with the _Tamaya server module_ . + + +=== Compatibility + +The module is based on Java 7, so it will not run on Java 7 and beyond. + + +=== Installation + +To benefit from configuration builder support you only must add the corresponding dependency to your module: + +[source, xml] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-remote</artifactId> + <version>{tamayaVersion}</version> +</dependency> +----------------------------------------------- + + +=== Reading Remote configuration from a Tamaya Configuration Server + +The remote module allows reading JSON formatted onfiguration as provided by the _Tamaya server extension_ . The JSON +format used looks as follows: + +[source, json] +----------------------------------------------- +{ + "java.vendor.url": "http://java.oracle.com/", + "java.vendor.url.bug": "http://bugreport.sun.com/bugreport/", + "java.vm.info": "mixed mode", + "java.vm.name": "Java HotSpot(TM) 64-Bit Server VM", + "java.vm.specification.name": "Java Virtual Machine Specification", + "java.vm.specification.vendor": "Oracle Corporation", + "java.vm.specification.version": "1.8", + "java.vm.vendor": "Oracle Corporation", + "java.vm.version": "25.45-b02", + "sun.arch.data.model": "64", + "sun.boot.class.path": "C:\apps\jdk18\jre\lib\resources.jar;C:\apps\jdk18\jre\lib\rt.jar;C:\apps\jdk18\jre\lib\sunrsasign.jar;C:\apps\jdk18\jre\lib\jsse.jar;C:\apps\jdk18\jre\lib\jce.jar;C:\apps\jdk18\jre\lib\charsets.jar;C:\apps\jdk18\jre\lib\jfr.jar;C:\apps\jdk18\jre\classes", + "sun.boot.library.path": "C:\apps\jdk18\jre\bin", + "sun.cpu.endian": "little", + "sun.cpu.isalist": "amd64", + "sun.desktop": "windows", + "sun.io.unicode.encoding": "UnicodeLittle", + "sun.java.command": "com.intellij.rt.execution.application.AppMain org.apache.tamaya.examples.remote.server.Start", + "sun.java.launcher": "SUN_STANDARD", + "sun.jnu.encoding": "Cp1252", + "sun.management.compiler": "HotSpot 64-Bit Tiered Compilers", + "sun.os.patch.level": "", + "{meta}class": "org.apache.tamaya.functions.FilteredConfiguration", + "{meta}info.filter": "java.v,sun", + "{meta}info.format": "application/json", + "{meta}info.timestamp": "1441463200571", + "{meta}timestamp": "1441463200571", + "{meta}type": "Configuration" +} +----------------------------------------------- + +Basically there are no constraints about they keys provided. By default Tamaya uses keys prefixed with ++{xxx}+ to identify meta-data entries, but this is not a required precondition. + +Finally such a remote configuration can be easily integrated by inheriting from the provided base +class. Hereby a default ordinal must be defined and the +protected Collection<URL> getAccessURLs()+ +method must be implemented to define the URL from where the configuration should be accessible. Hereby +multiple URLs can be provided, which are accesed in order as provided by the collection's iterator. The +first URL that is successfully accessed determines the configuration read and imported into the ++PropertySource+. + +[source, java] +----------------------------------------------- +public class RemotePropertySource extends BaseRemotePropertySource{ + /** Current remote property source default ordinal. */ + private static final int REMOTE_ORDINAL = 15000; + + @Override + public int getDefaultOrdinal(){ + return REMOTE_ORDINAL; + } + + @Override + protected Collection<URL> getAccessURLs() { + try { + String configServerUrl = System.getenv("CONFIG_SERVER"); + if(configServerUrl==null){ + configServerUrl = System.getProperty("configServer"); + } + if(configServerUrl==null){ + configServerUrl = "http://localhost:8888/config?scope=CLIENT&scopeId={clientId}&format=application/json"; + } + System.out.println("Reading config from " + configServerUrl.replace("{clientId}", Client.getClientId())); + return Arrays.asList(new URL[]{new URL(configServerUrl.replace("{clientId}", Client.getClientId()))}); + } catch (MalformedURLException e) { + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to configure remote config location,", e); + return Collections.emptySet(); + } + } + +} +----------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-site/blob/3d91bad5/content/extensions/mod_resolver.adoc ---------------------------------------------------------------------- diff --git a/content/extensions/mod_resolver.adoc b/content/extensions/mod_resolver.adoc new file mode 100644 index 0000000..6f8f93a --- /dev/null +++ b/content/extensions/mod_resolver.adoc @@ -0,0 +1,144 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + += Apache Tamaya -- Extension: Resolver + +// include::temp-properties-files-for-site/attributes.adoc[] +:jbake-type: page +:jbake-status: published + +[[Core]] +== Tamaya Resolver (Extension Module) + +=== Overview + +Tamaya Resolver is an extension module. Refer to the +// @todo Fix the link to the modules documentation +link:modules.html[extensions documentation] +for further details about modules. + +Tamaya Resolver provides a dynamic resolution mechanism, which allows to use UNIX-styled (+${...}+ placeholder +expressions in your configuration values. The resolver hereby supports transitive resolution and also prevents +cycles to loop endlessly. + +=== Compatibility + +The module is based on Java 7, so it can be used with Java 7 and beyond. + +=== Installation + +To benefit from dynamic value resolution you only must add the corresponding dependency to your module: + +[source, xml, subs="verbatim,attributes"] +----------------------------------------------- +<dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-resolver</artifactId> + <version>{tamaya_version_development}</version> +</dependency> +----------------------------------------------- + +The module automatically registers an according +PropertyFilter+ that is automatically called, whenever a value +is accessed. + +=== Available Resolvers + +Currently the module defined the following resolvers: + +.Available Resolvers +[cols="<.1,<.2,<.1"] +|======= +| _Expression_ +| _Description_ +| _Example_ + +| +conf:<configKey>+ +| Reads another configKey and replaces the expression with the value found. +| conf-ref=${conf:anotherConf.entryKey} + +| +resource:<resourceRef>+ +| Reads a resource from the current classpath and replaces the expression with the given text content. +| cp-ref=${resource:Testresource.txt} + +| +file:<fileRef>+ +| Reads a resource from the current classpath and replaces the expression with the given text content. +| file-ref=${file:c:\myFile.txt} + +|+url:<url>+ +|Reads an URL and replaces the expression with the given text content. +| url-ref=${url:http://www.google.com} + +|======= + +=== SPI: Implementing your own Resolvers + +The module also provides an easy but powerful SPI for adding your own resolver implementations. Basically the +first and most important thing to do is implementing the +ExpressionResolver+ interface: + +.Implementing a Custom Resolver +[source, java] +----------------------------------------------- +public class PwdDecrypter implements ExpressionResolver { + + @Override + public String getResolverPrefix() { + return "decrypt:"; + } + + @Override + public String evaluate(String expression) { + return decrypt(expression); + } + + private String decrypt(String s) { + ... + } +} +----------------------------------------------- + +Basically that is all you must do, after having registered the class with the +ServiceLoader+ it will be found +and loaded by the implementation. With that all expressions that start with the given prefix are passed to the +resolver, so all the following expressions will be sent to the implementation: + +[source,listing] +----------------------------------------------- +blabla ${decrypt:myname} +blabla ${decrypt:myname} foo blabla ${decrypt:myname} +----------------------------------------------- + +Hereby evaluation is repeated until no further change of values could be detetced. In case of a endless loop +the evaluation is broken after a (configurable) number of cycles. + + +Under the hood instances of +ExpressionResolver+ are managed by an implementation of the +ExpressionEvaluator+ +interface: + +[source, java] +----------------------------------------------- +public interface ExpressionEvaluator { + /** + * Evaluates the current expression. + * @param key the key, not null. + * @param value the value to be filtered/evaluated. + * @return the filtered/evaluated value, including null. + */ + String evaluateExpression(String key, String value); +} +----------------------------------------------- + +Implementing and registering this interface gives you full control, but in most cases yhou should be fine with +the default implementation in place.
