Hi all find following an additional part of use cases for comment. Note that this area IMO definitively may be improved in several ways. Always keep in mind that I try to setup the design guide similarly in parallel. It can be easily accessed from the GH mirror:
https://github.com/apache/incubator-tamaya/blob/master/docs/design/2_CoreConcepts.adoc Cheers, Anatole Combining Property Providers Looking at the structures of configuration system used by large companies we typically encounter some kind of configuration hierarchies that are combined in arbitrary ways. Users of the systems are typically not aware of the complexities in this area, since they simply know the possible locations, formats and the overriding policies. Framework providers on the other side must face the complexities and it would be very useful if Tamaya can support here by providing prebuilt functionality that helps implementing these aspects. All this leads to the feature set of combining property providers. Hereby the following strategies are useful: - aggregating providers, hereby later providers added - override any existing entries from earlier providers - combine conflicting entries from earlier providers, e.g. into a comma-separated structure. - may throw a ConfigExcepotion ig entries are conflicting - may only add entries not yet defined by former providers, preventing entries that are already present to be overwritte - any custom aggregation strategy, which may be a mix of above - intersecting providers - subtracting providers - filtering providers These common functionality is provided by the PropertyProviders singleton. Additionally to the base strategies above a MetaInfo instance can be passed optionally as well to define the meta information for the newly created provider instances. Let’s assume we have two property providers with the following data: Provider 1 a=a b=b c=c g=g h=h i=i Provider 2 a=A b=B c=C d=D e=E f=F Looking in detail you see that the entries a,b,c are present in both providers, whereas d,e,f are only present in provider 1, and g,h,i only in provider 2. Example Combining PropertyProviders PropertyProvider provider1 = ... PropertyProvider provider2 = ... // aggregate, hereby values from provider 2 override values from provider 1 PropertyProvider unionOverriding = PropertyProviders.aggregate(AggregationPolicy.OVERRIDE(), provider1, provider2);*System*.out.println("unionOverriding: " + unionOverriding); // ignore duplicates, values present in provider 1 are not overriden by provider 2 PropertyProvider unionIgnoringDuplicates = PropertyProviders.aggregate(AggregationPolicy.IGNORE_DUPLICATES(), provider1, provider2);*System*.out.println("unionIgnoringDuplicates: " + unionIgnoringDuplicates); // this variant combines/maps duplicate values into a new value PropertyProvider unionCombined = PropertyProviders.aggregate(AggregationPolicy.COMBINE(), provider1, provider2);*System*.out.println("unionCombined: " + unionCombined); // This variant throws an exception since there are key/value paris in both providers, but with different values*try*{ PropertyProviders.aggregate(AggregationPolicy.EXCEPTION(), provider1, provider2); }*catch*(ConfigException e){ // expected! } The example above produces the following outpout: Example Combining PropertyProviders AggregatedPropertyProvider{ (name = dynamicAggregationTests) a = "[a][A]" b = "[b][B]" c = "[c][C]" d = "[D]" e = "[E]" f = "[F]" g = "[g]" h = "[h]" i = "[i]" } unionOverriding: AggregatedPropertyProvider{ (name = <noname>) a = "A" b = "B" c = "C" d = "D" e = "E" f = "F" g = "g" h = "h" i = "i" } unionIgnoringDuplicates: AggregatedPropertyProvider{ (name = <noname>) a = "a" b = "b" c = "c" d = "D" e = "E" f = "F" g = "g" h = "h" i = "i" } unionCombined: AggregatedPropertyProvider{ (name = <noname>) a = "a,A" b = "b,B" c = "c,C" d = "D" e = "E" f = "F" g = "g" h = "h" i = "i" } No AggregationPolicy is also an interface that can be implemented: AggregationPolicy Interface @FunctionalInterface*public* *interface* *AggregationPolicy* { *String* aggregate(*String* key, *String* value1, *String* value2); } So we can also define our own aggregation strategy using a Lambda expression: Use a Custom AggregationPolicy PropertyProvider provider1 = ...; PropertyProvider provider2 = ...; PropertyProvider props = PropertyProviders.aggregate( (k, v1, v2) -> (v1 != null ? v1 : "") + '[' + v2 + "]", MetaInfo.of("dynamicAggregationTests"), props1, props2);*System*.out.println(props); Additionally we also pass here an instance of MetaInfo. The output of this code snippet is as follows: Listing of dynamic aggregation policy AggregatedPropertyProvider{ (name = dynamicAggregationTests) a = "[a][A]" b = "[b][B]" c = "[c][C]" d = "[D]" e = "[E]" f = "[F]" g = "[g]" h = "[h]" i = "[i]" } Summarizing the PropertyProviders singleton allows to combine providers in various forms: Methods provided on PropertyProviders public final class PropertyProviders { private PropertyProviders() {} public static PropertyProvider fromArgs(String... args) { public static PropertyProvider fromArgs(MetaInfo metaInfo, String... args) { public static PropertyProvider fromPaths(AggregationPolicy aggregationPolicy, String... paths) { public static PropertyProvider fromPaths(String... paths) { public static PropertyProvider fromPaths(List<String> paths) { public static PropertyProvider fromPaths(AggregationPolicy aggregationPolicy, List<String> paths) { public static PropertyProvider fromPaths(MetaInfo metaInfo, List<String> paths) { public static PropertyProvider fromPaths(AggregationPolicy aggregationPolicy, MetaInfo metaInfo, List<String> paths) { public static PropertyProvider fromUris(URI... uris) { public static PropertyProvider fromUris(AggregationPolicy aggregationPolicy, URI... uris) { public static PropertyProvider fromUris(List<URI> uris) { public static PropertyProvider fromUris(AggregationPolicy aggregationPolicy, List<URI> uris) { public static PropertyProvider fromUris(MetaInfo metaInfo, URI... uris) { public static PropertyProvider fromUris(AggregationPolicy aggregationPolicy, MetaInfo metaInfo, URI... uris) { public static PropertyProvider fromUris(MetaInfo metaInfo, List<URI> uris) { public static PropertyProvider fromUris(AggregationPolicy aggregationPolicy, MetaInfo metaInfo, List<URI> uris) { public static PropertyProvider fromMap(Map<String, String> map) { public static PropertyProvider fromMap(MetaInfo metaInfo, Map<String, String> map) { public static PropertyProvider empty() { public static PropertyProvider emptyMutable() { public static PropertyProvider empty(MetaInfo metaInfo) { public static PropertyProvider emptyMutable(MetaInfo metaInfo) { public static PropertyProvider fromEnvironmentProperties() { public static PropertyProvider fromSystemProperties() { public static PropertyProvider freezed(PropertyProvider provider) { public static PropertyProvider aggregate(AggregationPolicy mapping, MetaInfo metaInfo, PropertyProvider... providers){ public static PropertyProvider aggregate(PropertyProvider... providers) { public static PropertyProvider aggregate(List<PropertyProvider> providers) { public static PropertyProvider aggregate(AggregationPolicy mapping, PropertyProvider... propertyMaps) { public static PropertyProvider aggregate(AggregationPolicy mapping, List<PropertyProvider> providers) { public static PropertyProvider mutable(PropertyProvider provider) { public static PropertyProvider intersected(AggregationPolicy aggregationPolicy, PropertyProvider... providers) { public static PropertyProvider intersected(PropertyProvider... providers) { public static PropertyProvider subtracted(PropertyProvider target, PropertyProvider... providers) { public static PropertyProvider filtered(Predicate<String> filter, PropertyProvider provider) { public static PropertyProvider contextual(Supplier<PropertyProvider> mapSupplier, Supplier<String> isolationKeySupplier) { public static PropertyProvider delegating(PropertyProvider mainMap, Map<String, String> parentMap) { public static PropertyProvider replacing(PropertyProvider mainMap, Map<String, String> replacementMap) { }
