:jbake-type: page
:jbake-status: published

[[Core]]
== Apache Tamaya: Core Implementation
=== Overview

`tamaya-core` provides an implementation of the link:api.html[Tamaya Configuration API] and adds additional functionality
and building blocks for supporting SPI implementations.

Tamaya Core contains the following artifacts:

* A service loader implementation, configurations and further logic required to run
  in an OSGI environment.
* Numerous *converters*, including an +EnumConverter+, that is a converter implementation that can automatically select
  the currect enumeration values based on a configured entry.
* A configurable `BannerManager`to print Tamaya's start logo on load.

Basically `tamaya-core` leverages the base implementations contained in Tamaya's SPI support module, so it is quite
small in size. All required components are implemented and registered, so basically the
Core module with its trasitive dependencies (API and spi-support) is a complete configuration solution. Nevertheless
it is also very minimalistic, but fortunately it can be easily extended/accommodated with additional features as needed.

These extensions are managed in the extensions repository of the Tamaya project. Some of the most commonly used
extensions are

* placeholder and resolution mechanisms (+org.apache.tamaya.ext:tamaya-resolver+)
* dynamic resource path lookup, e.g. with ant styled patterns (+org.apache.tamaya.ext:tamaya-resources+)
* configuration injection and configuration templates (+org.apache.tamaya.ext:tamaya-injcetion-api+)
* abstraction for reusable formats (+org.apache.tamaya.ext:tamaya-formats+)
* integration with other existing solutions (e.g. +org.apache.tamaya.ext:tamaya-spring+)
* configuration and configuration isolation targeting Java EE (+org.apache.tamaya.ext:tamaya-injection-ee+)
* dynamic configuration and configuration updates (+org.apache.tamaya.ext:tamaya-events+)

For details about the extension modules available and  their functionality refer to the link:extensions.html[extension
user guide].


[[CorePropertyConverters]]
=== Default PropertyConverters

The `tamaya-core` module provides several +PropertyConverter+ implementations, which are automatically registered:

[width="100%",frame="1",options="header",grid="all"]
|=======
|_Target Type_              |_Class Name_              |_Supported Formats_
|java.math.BigDecimal       |BigDecimalConverter       |1.2345, 0xFF
|java.math.BigInteger       |BigIntegerConverter       |0xFF, 1234
|java.ui.lang.Boolean       |BooleanConverter          |true, false, T, F, 1 ,0
|java.ui.lang.Byte          |ByteConverter             |0xFF, MIN_VALUE, MAX_VALUE, 123
|java.ui.lang.Character     |CharConverter             |0xFF, 'a', 'H', 123
|java.ui.lang.Class         |ClassConverter            |<fully qualified class name>
|java.util.Currency         |CurrencyConverter         |CHF, 123
|java.ui.lang.Double        |DoubleConverter           |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY, MIN_VALUE, MAX_VALUE
|java.time.Duration         |DurationConverter         |<Duration as defined by Duration.parse(String)>
|java.io.File               |FileConverter             |value -> new File(value)
|java.ui.lang.Float         |FloatConverter            |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY, MIN_VALUE, MAX_VALUE
|java.time.Instant          |InstantConverter          |<Instant as defined by Instant.parse(String)>
|java.ui.lang.Integer       |IntegerConverter          |1, 0xD3, MIN_VALUE, MAX_VALUE
|java.time.LocalDate        |LocalDateConverter        |<Date as defined by LocalDate.parse(String)
|java.time.LocalDateTime    |LocalDateTimeConverter    |<LocalDateTime as defined by LocalDateTime.parse(String)>
|java.time.LocalTime        |LocalTimeConverter        |<Time as defined by LocalTime.parse(String)
|java.ui.lang.Long          |LongConverter             |1, 0xD3, MIN_VALUE, MAX_VALUE
|java.ui.lang.Number        |NumberConverter           |1, 0xFF, 1.2334, NaN, NEGATIVE_INFITIY, POSITIVE_INFINITY
|java.time.OffsetDateTime   |OffsetDateTimeConverter   |<OffsetDateTime as defined by OffsetDateTime.parse(String)>
|java.time.OffsetTime       |OffsetTimeConverter       |<OffsetTime as defined by OffsetTime.parse(String)>
|java.util.Optional         |OptionalConverter         |
|java.nio.Path              |PathConverter             |
|java.ui.lang.Short         |ShortConverter            |1, 0xD3, MIN_VALUE, MAX_VALUE
|java.util.Supplier         |SupplierConverter         |
|java.net.URI               |URIConverter              |http://localhost:2020/testresource?api=true
|java.net.URL               |URLConverter              |http://localhost:2020/testresource?api=true
|_Enums_                    |EnumConverter             |<Enum item name>
|=======


=== Registering PropertyConverters

Additional +PropertyConverter+ classes can be implemented easily. It is recommended to register them using
the +java.util.ServiceLoader+, meaning you add a file under +META-INF/service/org.apache.tamaya.spi.PropertyConverter+
containing the fully qualified class names of the converters to be registered (one line each) to enable
auto-discovery.

Alternatively you can also use a +ConfigurationBuilder+ to add additional converters
programmatically.


[[ComponentLoadingAndPriorization]]
=== Component Loading and Priorization

Tamaya _Core_ in general loads all components by default using the +java.util.ServiceLoader+ mechanism. This means that
new components must be registered by adding a file under +META-INF/service/<myInterfaceName>+ containing the fully
qualified implementation class names of the components to be registered (one line per each).
The +ServiceLoader+ itself does not provide any functionality for overriding or ordering of
components. Tamaya _Core_ adds such a functionality with the possibility to add +@Priority+
annotations to the components registered. By default, and if no annotation is added +0+ is assumed
as priority. Hereby higher values preceed lower values, meaning

* if a _singleton_ component is accessed from the current +ServiceContext+ the component with the
  higher value effectively _overrides/replaces_ any component with lower values.
* if a _collection_ of components is obtained from the +ServiceContext+ the components are _ordered_
  based on their priorities, where the ones with higher priority are before components with lower
  priority.
* if priorities _match_ Tamaya _Core_ additionally sorts them using the _simple class name_.
  This ensures that ordering is still defined and predictable in all scenarios.

NOTE: Sorting the property sources based on their ordinal value is only the default ordering
      principle applied. By implementing your own implementation of +ConfigurationProviderSpi+
      you can apply a different logic:


[[RegisteringPropertySources]]
=== Registering Property Sources

+PropertySource+ implementations that provide configuration properties are registered as components as described in the
previous section. Hereby the precedence (ordering) of property sources is not hard-coded. Instead a +Comparator<PropertySource>+
can be passed to a +ConfigurationBuilder+ to perform automatic ordering of the property sources
registered. The default implementation hereby implements the following logic:

. It checks for an property entry +tamaya.ordinal+ if present the value is parsed into an +int+ value and used as
  the ordinal val value.
. It checks for an explicit method +int getOrdinal()+, if found its value is taken as an ordinal.
. It checks for a +@Priority+ annotation, if present the priority value is used as an ordinal.
. If none of the above works, +0+ is assumed as ordinal value.
. If multiple +PropertySource+ instances share the same ordinal value, they are ordered based on their fully qualified
  class names.

Custom implementations of the property source comparator can be applied by calling
+ConfigurationContextBuilder.sortPropertySources(Comparator<PropertySource>)+. The default comparator can be replaced
by passing the fully qualified comparator class name as system property:

+-Dproperty-source-comparator=a.b.c.MyComparatorClass+

The ladder allows to adapt the ordering of auto-discovered property sources, even if the value returned by
+int getOrdinal()+ cannot be changed.


[[CorePropertySources]]
== Configuration Setup in Core

Tamaya Core provides a minimal configuration setting, that allows you to configure SE
applications already easily. Basically configuration is built  up by default as follows:

. Read environment properties and add them prefixed with +env.+
. Read all files found at +META-INF/javaconfiguration.properties+
  and +META-INF/javaconfiguration.xml+


=== Overview of Registered Default Property Sources and Providers

The Tamaya Core implementation provides a couple of default +PropertySource+ implementations, which are automatically
registered. They are all in the package +org.apache.tamaya.spisupport.propertysource+ and
+org.apache.tamaya.core.provider+:

[width="100%",frame="1",options="header",grid="all"]
|=======
|_Type_                                   |_Class Name_                   |_Ordinal Used_
|META-INF/javaconfiguration.properties    |JavaConfigurationProvider      |100
|META-INF/javaconfiguration.xml           |JavaConfigurationProvider      |100
|JNDI Entries                             |JNDIPropertySource             |200
|Environment Properties                   |EnvironmentPropertySource      |300
|System Properties                        |SystemPropertySource           |1000
|=======

NOTE: Similarly to property converters the property sources shown here are defined within the "tamaya-spisupport* module
      and automatically registered with the *tamaya-core* implementation using Tamaya's auto-discovery mechanisms.

NOTE: +JNDIPropertySource+ is provided by the `tamaya-jndi` extension module.


=== Abstract Class PropertiesFilePropertySource

The abstract class +PropertiesFilePropertySource+ can be used for implementing a +PropertySource+ based on a +URL+
instance that points to a +.properites+ file. It requires a +URL+ to be passed on the constructor:

[source,java]
--------------------------------------------
PropertiesFilePropertySource(URL url);
--------------------------------------------


==== Abstract Class PropertiesPropertySource

The abstract class +PropertiesPropertySource+ can be used for implementing a +PropertySource+ based on a +Properties+
instance. It requires a +PropertySource+ to be passed on the constructor:

[source,java]
--------------------------------------------
PropertiesPropertySource(Properties properties);
--------------------------------------------


==== Abstract Class BasePropertySource

The abstract class +BasePropertySource+ can be used for implementing custom +PropertySource+ classes. It requires only
one method to implemented:

[source,java]
.Implementing a PropertySource using BasePropertySource
--------------------------------------------
public class MyPropertySource extends BasePropertySource{

    public String getName(){
        // return a unique name for the property source, e.g. based on the underlying resource. This name also
        // allows to access the property source later
    }

    public Map<String, String> getProperties(){
        // Get a map with all properties provided by this property source
        // If the property source is not scannable, the map returned may be empty.
        // In the ladder case the +boolean isScannale()+ must be overridden, since
        // by default property sources are assumed to be scannable.
    }

}
--------------------------------------------

By default the ordinal of the property sources will be 1000, unless the key +tamaya.ordinal+
as defined in +PropertySource.TAMAYA_ORDINAL+ is present in the current +PropertySource+. Of course
it is also possible to override the inherited +protected void initializeOrdinal(final int defaultOrdinal)+,
or directly +int getOrdinal()+.


[[CorePropertySourceProviders]]
=== Default PropertySourceProvider in Core

With +org.apache.tamaya.core.provider.JavaConfigurationProvider+ there is also a default +PropertySourceProvider+
present that loads all +.properties+ files found at +META-INF/javaconfiguration.properties+
and +META-INF/javaconfiguration.xml+.


=== Replacing the property value evaluation policy

Tamaya's core implementation allows to replace the complete logic how a configuration value or the current configuration
properties are calculated from a given +ConfigurationContext+ by implementing the +ConfigValueEvaluator+
interface:

[source,java]
--------------------------------------------
/**
 * Component SPI which encapsulates the evaluation of a single or full <b>raw</b>value
 * for a {@link ConfigurationContext}.
 */
public interface ConfigValueEvaluator {

    /**
     * Evaluates single value using a {@link ConfigurationContext}.
     * @param key the config key, not null.
     * @param context the context, not null.
     * @return the value, or null.
     */
    PropertyValue evaluteRawValue(String key, ConfigurationContext context);

    /**
     * Evaluates all property values from a {@link ConfigurationContext}.
     * @param context the context, not null.
     * @return the value, or null.
     */
    Iterable<PropertyValue> evaluateRawValues(ConfigurationContext context);

}
--------------------------------------------

The default implementation +DefaultConfigValueEvaluator+ implements the following logic:

. Collect all +PropertySources+ from the context.
. Access +PropertyValue get(String)+ (single key access)/ +Map<String,PropertyValue> getProperties()+
  (config map access) from each property source and combines the previous with the next value.

The resulting _raw_ value(s) are then finally handed over to the registered filters and finally
converted to the target type as required by the user API.


[[Extensions]]
== Adding Extensions

Tamaya _Core_ only implements the link:api.html[API]. Many users require/wish additional functionality from a
configuration system. Fortunately there are numerous extensions available that add further functionality.
Loading extensions hereby is trivial: you only are required to add the corresponding dependency to the classpath.

For detailed information on the extensions available refer to the link:extensions.html[extensions documentation].
