Skip to content

Commit

Permalink
refs: eclipse#384 backport spec wording fixes and enhancements from C…
Browse files Browse the repository at this point in the history
…onfigJSR

All changes originally by me, except 1 smallish fixes by Tomas Langer.
  • Loading branch information
struberg committed Sep 4, 2018
1 parent a0ae595 commit 442525f
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 33 deletions.
12 changes: 7 additions & 5 deletions spec/src/main/asciidoc/architecture.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ It also defines ways to extend the configuration mechanism itself via a SPI (Ser

=== Rationale

Released binaries often contain functionality which need to behave slightly differently depending on the deployment.
This might be different REST endpoints to talk to (e.g. depending on the customer for whom a WAR is deployed).
Released binaries often contain functionality which needs to behave slightly differently depending on the deployment.
This might be the port numbers and URLs of REST endpoints to talk to (e.g. depending on the customer for whom a WAR is deployed).
Or it might even be whole features which need to be switched on and off depending on the installation.
All this must be possible without the need to re-package the whole application binary.

Microprofile-Config provides a way to achieve this goal by aggregating configuration from many different <<configsource,ConfigSources>> and presents a single merged view to the user.
This allows the application to bundle default configuration within the application.
It also allows to override the defaults from outside, e.g. via an environment variable a Java system property or via Docker.
It also allows to override the defaults from outside, e.g. via an environment variable a Java system property or via a container like Docker.
Microprofile-Config also allows to implement and register own configuration sources in a portable way, e.g. for reading configuration values from a shared database in an application cluster.


Internally, the core Microprofile-Config mechanism is purely String/String based.
Type-safety is only provided on top of that by using the proper <<Converter,Converters>> before handing the value out to the caller.
Type-safety is intentionally only provided on top of that by using the proper <<Converter,Converters>> before handing the value out to the caller.

The configuration key might use dot-separated to prevent name conflicts. This is similar to Java package namespacing:
The configuration key might use dot-separated blocks to prevent name conflicts. This is similar to Java package namespacing:

[source, text]
----
Expand All @@ -50,3 +50,5 @@ some.library.own.config=some value
----


TIP: while the above example is in the java property file syntax the actual content could also e.g. be read from a database.

65 changes: 65 additions & 0 deletions spec/src/main/asciidoc/configaccessor.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// Copyright (c) 2016-2018 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Contributors:
// Mark Struberg

[[configaccessor]]
== ConfigAccessor


The `ConfigAccessor` API is intended for typed configuration values and precise control over resolution.

=== ConfigAccessor Usage

The simplest usage of the API is resolution of a String property, equivalent to a call to `Config.getValue(propertyKey, String.class)`.
This can also be handled via `ConfigAccessor` as shown in the following example:

.Simple example of ConfigAccessor
[source,java]
-----------------------------------------------------------------
String userName = config.access("user.name").getValue();
-----------------------------------------------------------------

Additional to this the `ConfigAccessor` also allows for far more complex control over the access to configured values.

The call to `config.access(..)` returns a `ConfigAccessor`.
This is basically a builder which has methods to refine the resolution, including the following:

* `as(Class<N> clazz)` -- defines the return type of the property
* `asList()` -- Declare the ConfigAccessor to return a List of the given Type.
* `evaluateVariables(boolean evaluateVariables)`
* `useConverter(Converter<T> converter)` -- Defines a specific {@link Converter} to be used instead of applying the default Converter resolving logic.
* `withLookupSuffix(String postfixName)` -- sets a parameter for the resolution of a 'postfix' for the resolution
* `withLookupSuffix(ConfigAccessor)` -- you can also use a `ConfigAccessor` to determine the 'postfix' for the resolution
* `withDefault(T value)` -- sets the default value, used in case the resolution returns `null`
* `getValue()` -- returns the resolved value with the appropriate type

.A more complete example of ConfigAccessor
[source,java]
-----------------------------------------------------------------
Config config = ConfigProvider.getConfig();
ConfigAccessor<Integer> dbPortCfg
= config.access("db.port")
.as(Integer.class)
.addLookupSuffix(config.access("project.projectStage").cacheFor(12, TimeUnit.HOURS))
.addLookupSuffix("database.vendor")
.withDefault(3306);
...
Integer port = dbPortCfg.getValue();
-----------------------------------------------------------------
10 changes: 7 additions & 3 deletions spec/src/main/asciidoc/configexamples.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
// Emily Jiang

[[configexamples]]
== Configuration Usage Examples
== Config Usage Examples


A configuration object can be obtained programmatically via the `ConfigProvider` or automatically via `@Inject Config`. An application can then access its configured values via a `Config` instance.
An application can obtain it's configuration programmatically via the `ConfigProvider`.
In CDI enabled beans it can also get injected via `@Inject Config`.
An application can then access its configured values via this `Config` instance.

=== Simple Programmatic Example

Expand All @@ -42,7 +44,7 @@ public class ConfigUsageSample {
}
----

If you need to access a different server then you can e.g. change the configuration via a `-D` system property:
If you need to access a different server then you can e.g. change the configuration via a Java `-D` system property:

[source, text]
----
Expand Down Expand Up @@ -77,12 +79,14 @@ public class InjectedConfigUsageSample {
@Inject
@ConfigProperty(name="myprj.some.url")
private String someUrl;
//The following code injects an Optional value of myprj.some.port property.
//Contrary to natively injecting the configured value this will not lead to a
//DeploymentException if the configured value is missing.
@Inject
@ConfigProperty(name="myprj.some.port")
private Optional<Integer> somePort;
//Injects a Provider for the value of myprj.some.dynamic.timeout property to
//resolve the property dynamically. Each invocation to Provider#get() will
//resolve the latest value from underlying Config.
Expand Down
12 changes: 10 additions & 2 deletions spec/src/main/asciidoc/configsources.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,20 @@ It can also be used to implement a drop-in configuration approach.
Simply create a jar containing a `ConfigSource` with a higher ordinal and override configuration values in it.
If the jar is present on the classpath then it will override configuration values from <<ConfigSource,ConfigSources>> with lower `ordinal` values.

=== Manually defining the Ordinal of a built-in ConfigSource

Note that a special property `config_ordinal` can be set within any built-in `ConfigSource` implementation.
The default implementation of `getOrdinal()` will attempt to read this value.
If found and a valid integer, the value will be used.
Otherwise the respective default value will be used.

[source, text]
----
config_ordinal = 120
com.acme.myproject.someserver.url = http://more_important.server/some/endpoint
----


Note that `config_ordinal` can be set within any `ConfigSource` implementation. The default implementation of `getOrdinal()` will attempt to read this value, if found and a valid integer, the value will be used, otherwise the default of `100` will be returned.

[[default_configsources]]
=== Default ConfigSources

Expand Down Expand Up @@ -142,6 +147,9 @@ public class ExampleYamlConfigSourceProvider

Please note that a single `ConfigSource` should be either registered directly or via a `ConfigSourceProvider`, but never both ways.

=== Cleaning up a ConfigSource

If a `ConfigSource` implements the `java.lang.AutoCloseable` interface then the `close()` method will be called when the underlying `Config` is being released.

=== ConfigSource and Mutable Data

Expand Down
70 changes: 49 additions & 21 deletions spec/src/main/asciidoc/converters.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The following `Converter` s are provided by Microprofile-Config by default:
* `float` and `Float` , a dot '.' is used to separate the fractional digits
* `double` and `Double` , a dot '.' is used to separate the fractional digits
* `Class` based on the result of `Class.forName`
* `URL`

All built-in `Converter` have the `@Priority` of `1`.

Expand All @@ -54,41 +55,68 @@ The `Config` will use the `Converter` with the highest `Priority` for each targe
A custom `Converter` for a target type of any of the built-in Converters will overwrite the default Converter.

Converters can be added to the `ConfigBuilder` programmatically via `ConfigBuilder#withConverters(Converter<?>... converters)`
where the type of the converters can be obtained via reflection. However, this is not possible for a lambda converter. In this case, use the method `ConfigBuilder#withConverter(Class<T> type, int priority, Converter<T> converter)`.
where the type of the converters can be obtained via reflection. However, this is not possible for a lambda converter.
In this case, use the method `ConfigBuilder#withConverter(Class<T> type, int priority, Converter<T> converter)`.

=== Implicit Converters

If no built-in nor custom `Converter` for a requested Type `T`, an implicit Converter is automatically provided if the following conditions are met:

!TODO rule option A:
* The target type {@code T} has a {@code public static T of(String)} method, or
* The target type {@code T} has a {@code public static T valueOf(String)} method, or
* The target type {@code T} has a public Constructor with a String parameter, or
* The target type {@code T} has a {@code public static T parse(CharSequence)} method

!TODO rule option B:
* The target type `T` has a Constructor with a String parameter, or
* the target type `T` has a Constructor with a CharSequence parameter, or
* the target type `T` has a `static T valueOf(String)` method, or
* the target type `T` has a `static T valueOf(CharSequence)` method, or
* the target type `T` has a `static T parse(String)` method, or
* the target type `T` has a `static T parse(CharSequence)` method, or

The lookup will be done in the order of the above list.

Note that every `java.time` type has a `parse(CharSequence)` method and every enum has a generated 'valueOf(String)' method.
They are thus all covered by an implicit converter!

If an Implicit Converter cannot convert a value, a `java.lang.IllegalArgumentException` is to be thrown.

=== Array Converters
For the built-in converters and custom converters, the corresponding Array converters are provided
by default. The delimiter for the config value is ",". The escape character is "\".

e.g. With this config `myPets=dog,cat,dog\\,cat`, the values as an array will be
`{"dog", "cat", "dog,cat"}`.
For the built-in converters and custom converters, the corresponding Array converters are provided by default.
The delimiter for the config value is ",".
The escape character is "\".
e.g. With this config `myPets=dog,cat,dog\,cat`, the values as an array will be `{"dog", "cat", "dog,cat"}`.

* Programmatic lookup
An array as a class is supported in the programmatic lookup.
==== Programmatic lookup

Array as a class type is supported in the programmatic lookup.

[source, java]
----
private String[] myPets = config.getValue("myPets", String[].class);
String[] myPets = config.getValue("myPets", String[].class);
----
myPets will be "dog", "cat", "dog,cat" as an array

* Injection model
For the property injection, Array, List and Set should be supported.
myPets will be "dog", "cat", "dog,cat" as an array

==== Injection model

For the property injection, Array, List and Set are supported.

[source, java]
----
@Inject @ConfigProperty(name="myPets") private String[] myArrayPets;
@Inject @ConfigProperty(name="myPets") private List<String> myListPets;
@Inject @ConfigProperty(name="myPets") private Set<String> mySetPets;
@Inject @ConfigProperty(name="myPets") String[] myPetsArray;
@Inject @ConfigProperty(name="myPets") List<String> myPetsList;
@Inject @ConfigProperty(name="myPets") Set<String> myPetsSet;
----
myPets will be "dog", "cat", "dog,cat" as an array, List or Set.

=== Automatic Converters
myPets will be "dog", "cat", "dog,cat" as an array, List or Set.

=== Cleaning up a Converter

If a `Converter` implements the `java.lang.AutoCloseable` interface then the `close()` method will be called when the underlying `Config` is being released.

If no built-in nor custom `Converter` for a requested Type `T`, an implicit Converter is automatically provided if the following conditions are met:

* The target type {@code T} has a {@code public static T of(String)} method, or
* The target type {@code T} has a {@code public static T valueOf(String)} method, or
* The target type {@code T} has a public Constructor with a String parameter, or
* The target type {@code T} has a {@code public static T parse(CharSequence)} method

2 changes: 1 addition & 1 deletion spec/src/main/asciidoc/license-alv2.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Status: {revremark}
Release: {revdate}
Copyright (c) 2016-2017 Contributors to the Eclipse Foundation
Copyright (c) 2016-2018 Contributors to the Eclipse Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
4 changes: 3 additions & 1 deletion spec/src/main/asciidoc/microprofile-config-spec.asciidoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2016-2017 Eclipse Microprofile Contributors:
// Copyright (c) 2016-2018 Eclipse Microprofile Contributors:
// Mark Struberg
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -46,4 +46,6 @@ include::configsources.asciidoc[]

include::converters.asciidoc[]

include::configaccessor.asciidoc[]

include::release_notes.asciidoc[]
17 changes: 17 additions & 0 deletions spec/src/main/asciidoc/release_notes.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,20 @@ More CTS were added:

Java2 security related change (link:https://github.com/eclipse/microprofile-config/issues/343[#343])


[[release_notes_14]]
== Release Notes for MicroProfile Config 1.4

The following changes occurred in the 1.4 release, compared to 1.2

A full list of changes may be found on the link:https://github.com/eclipse/microprofile-config/milestone/5?closed=1[MicroProfile Config 1.4 Milestone]

=== API/SPI Changes

MicroProfile 1.4 introduced a way to deal with dynamic values.
To support this feature from the user side we introduced the `ConfigAccessor`.
We also introduced a way to have `ConfigSources` notify the `Config` about an underlying attribute change.

=== Functional Changes

OSGi compatibility got improved.

0 comments on commit 442525f

Please sign in to comment.