Adapted to comply with JSR API, fixed bugs. Imrpved API regarding sections, section filtering.
Signed-off-by: Anatole Tresch <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/commit/36b44661 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/tree/36b44661 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/diff/36b44661 Branch: refs/heads/configjsr Commit: 36b446614d7c95b2ed1db9e15ff6ddaeeca1f7ab Parents: 581c92e Author: Anatole Tresch <[email protected]> Authored: Wed Dec 27 12:37:03 2017 +0100 Committer: Anatole Tresch <[email protected]> Committed: Wed Dec 27 12:37:03 2017 +0100 ---------------------------------------------------------------------- modules/functions/pom.xml | 5 +- .../tamaya/functions/ConfigSourceFunctions.java | 451 +++++++++++++++++++ .../functions/ConfigurationFunctions.java | 2 +- .../tamaya/functions/EnrichedConfigSource.java | 93 ++++ .../functions/EnrichedPropertySource.java | 103 ----- .../tamaya/functions/FilteredConfigSource.java | 89 ++++ .../functions/FilteredPropertySource.java | 93 ---- .../tamaya/functions/MappedConfigSource.java | 109 +++++ .../tamaya/functions/MappedPropertySource.java | 119 ----- .../functions/PropertySourceFunctions.java | 410 ----------------- .../functions/ValueMappedConfigSource.java | 75 +++ .../functions/ValueMappedPropertySource.java | 86 ---- .../functions/CombinedConfigurationTest.java | 1 - .../functions/ConfigSourceFunctionsTest.java | 434 ++++++++++++++++++ .../functions/EnrichedConfigSourceTest.java | 216 +++++++++ .../functions/EnrichedConfigurationTest.java | 4 - .../functions/EnrichedPropertySourceTest.java | 250 ---------- .../functions/FilteredConfigSourceTest.java | 188 ++++++++ .../functions/FilteredPropertySourceTest.java | 214 --------- .../tamaya/functions/InMemoryConfigSource.java | 68 +++ .../tamaya/functions/InMemoryConfiguration.java | 35 -- .../functions/InMemoryPropertySource.java | 86 ---- .../functions/MappedConfigSourceTest.java | 159 +++++++ .../functions/MappedPropertySourceTest.java | 176 -------- .../functions/PropertySourceFunctionsTest.java | 367 --------------- .../functions/ValueMappedConfigSourceTest.java | 148 ++++++ .../ValueMappedPropertySourceTest.java | 183 -------- 27 files changed, 2033 insertions(+), 2131 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/pom.xml ---------------------------------------------------------------------- diff --git a/modules/functions/pom.xml b/modules/functions/pom.xml index 17de980..4baa580 100644 --- a/modules/functions/pom.xml +++ b/modules/functions/pom.xml @@ -41,10 +41,9 @@ under the License. </dependency> <dependency> <groupId>org.apache.tamaya</groupId> - <artifactId>tamaya-spisupport</artifactId> - <version>${project.version}</version> + <artifactId>tamaya-base</artifactId> + <version>${tamaya-apicore.version}</version> </dependency> - <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java new file mode 100644 index 0000000..90081ed --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigSourceFunctions.java @@ -0,0 +1,451 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + +import javax.config.ConfigProvider; +import javax.config.spi.ConfigSource; +import java.util.*; +import java.util.function.Function; + +/** + * Accessor that provides useful functions along with configuration. + */ +public final class ConfigSourceFunctions { + /** + * Implementation of an empty propertySource. + */ + private static final ConfigSource EMPTY_PROPERTYSOURCE = new ConfigSource() { + + @Override + public int getOrdinal() { + return 0; + } + + @Override + public String getName() { + return "<empty>"; + } + + @Override + public String getValue(String key) { + return null; + } + + @Override + public Map<String, String> getProperties() { + return Collections.emptyMap(); + } + + @Override + public String toString() { + return "ConfigSource<empty>"; + } + }; + + + private static final Function<String,Integer> DEFAULT_AREA_CALCULATOR = + s -> s.lastIndexOf('.'); + + /** + * Private singleton constructor. + */ + private ConfigSourceFunctions() { + } + + /** + * Calculates the current section key and compares it to the given key. + * + * @param key the fully qualified entry key, not null + * @param sectionKey the section key, not null + * @param sectionCalculator function to calculate the split point of a key's section, e.g. {@code key.lastIndexOf('.')}, + * not null. + * @param directChildrenOnly if true, only keys with the same area match. Otherwise also containing super-areas can + * match. + * @return true, if the entry is exact in this section + */ + private static boolean isKeyInSection(String key, String sectionKey, + Function<String,Integer> sectionCalculator, boolean directChildrenOnly) { + Objects.requireNonNull(key, "Key must be given."); + Objects.requireNonNull(sectionCalculator, "Section calculator must be given."); + Objects.requireNonNull(sectionKey, "Section key must be given."); + + sectionKey = normalizeSectionKey(sectionKey); + + int lastIndex = sectionCalculator.apply(key); + String curAreaKey = lastIndex > 0 ? key.substring(0, lastIndex) : ""; + if(directChildrenOnly) { + return curAreaKey.equals(sectionKey); + }else{ + return curAreaKey.startsWith(sectionKey); + } + } + + private static String normalizeKey(String key) { + return normalizeKey(key, DEFAULT_AREA_CALCULATOR); + } + + private static String normalizeKey(String key, Function<String,Integer> sectionCalculator) { + if(key.isEmpty()){ + return key; + } + int index = sectionCalculator.apply(key.substring(0,1)); + if(index==0){ + return key.substring(1); + } + return key; + } + + private static String normalizeSectionKey(String sectionKey) { + return normalizeSectionKey(sectionKey, DEFAULT_AREA_CALCULATOR); + } + + private static String normalizeSectionKey(String sectionKey, Function<String,Integer> areaCalculator) { + // Ignore unneeded and trailing dot at the end of the section key + if(sectionKey.isEmpty()){ + return sectionKey; + } + int lastIndex = areaCalculator.apply(sectionKey); + int firstIndex = areaCalculator.apply(sectionKey.substring(0,1)); + + String normalizedKey = lastIndex==(sectionKey.length()-1) + ? sectionKey.substring(0, sectionKey.length() - 1) + : sectionKey; + + normalizedKey = firstIndex==0 ? sectionKey.length() == 1 ? "" + : normalizedKey.substring(1) + : normalizedKey; + + return normalizedKey; + } + + /** + * Checks if the given key is <i>directly</i> included in one of the given sections. + * + * @param key the fully qualified entry key, not {@code null} + * @param sectionKeys the section keys, not {@code null} + * @return true, if the entry is in one of the given sections + */ + public static boolean isKeyInSection(String key, String... sectionKeys) { + return isKeyInSection(key, true, DEFAULT_AREA_CALCULATOR, sectionKeys); + } + + /** + * Checks if the given key is included in one of the given sections. + * + * @param key the fully qualified entry key, not {@code null} + * @param sectionKeys the section keys, not {@code null} + * @param directChildrenOnly if true, then only keys match, which are a direct child of the given section. + * @return true, if the entry is in one of the given sections + */ + public static boolean isKeyInSection(String key, boolean directChildrenOnly, String... sectionKeys) { + return isKeyInSection(key, directChildrenOnly, DEFAULT_AREA_CALCULATOR, sectionKeys); + } + + /** + * Checks if the given key is included in one of the given sections, using the given separator to identify sections. + * + * @param key the fully qualified entry key, not {@code null} + * @param sectionKeys the section keys, not {@code null} + * @param areaCalculator the function to calculate the split point to identify the section of a key. + * @param directChildrenOnly if true, then only keys match, which are a direct child of the given section. + * @return true, if the entry is in one of the given sections + */ + public static boolean isKeyInSection(String key, boolean directChildrenOnly, + Function<String,Integer> areaCalculator, String... sectionKeys) { + Objects.requireNonNull(key, "Key must be given."); + Objects.requireNonNull(sectionKeys, "Section keys must be given."); + + for (String areaKey : sectionKeys) { + if (areaKey == null) { + continue; + } + if (isKeyInSection(key, areaKey, areaCalculator, directChildrenOnly)) { + return true; + } + } + return false; + } + + /** + * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible, + * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage + * does not support key iteration. + * + * @param properties properties to find sections in. + * @return set with all sections, never {@code null}. + */ + public static Set<String> sections(Map<String, String> properties) { + return sections(properties, DEFAULT_AREA_CALCULATOR); + } + + /** + * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible, + * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage + * does not support key iteration. + * + * @param properties properties to find sections in. + * @return set with all sections, never {@code null}. + */ + public static Set<String> sections(Map<String, String> properties, Function<String,Integer> areaCalculator) { + final Set<String> areas = new HashSet<>(); + for (String key : properties.keySet()) { + String normalizedKey = normalizeKey(key, areaCalculator); + + int index = areaCalculator.apply(normalizedKey); + if (index > 0) { + areas.add(normalizedKey.substring(0, index)); + } else { + areas.add("<root>"); + } + } + return areas; + } + + /** + * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all + * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate + * as possible, but may not provide a complete set of sections that are finally accessible, especially when the + * underlying storage does not support key iteration. + * + * @param properties properties to find transitive sections in. + * @return s set with all transitive sections, never {@code null}. + */ + public static Set<String> transitiveSections(Map<String, String> properties) { + return transitiveSections(properties, DEFAULT_AREA_CALCULATOR); + } + + /** + * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all + * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate + * as possible, but may not provide a complete set of sections that are finally accessible, especially when the + * underlying storage does not support key iteration. + * + * @param properties properties to find transitive sections in. + * @return s set with all transitive sections, never {@code null}. + */ + public static Set<String> transitiveSections(Map<String, String> properties, Function<String,Integer> areaCalculator) { + final Set<String> transitiveAreas = new HashSet<>(); + for (String section : sections(properties, areaCalculator)) { + section = normalizeSectionKey(section, areaCalculator); + + int index = areaCalculator.apply(section); + if (index < 0 && section.isEmpty()) { + transitiveAreas.add("<root>"); + } if (index < 0) { + transitiveAreas.add(section); + } else { + while (index > 0) { + section = section.substring(0, index); + transitiveAreas.add(section); + index = section.lastIndexOf('.'); + } + } + } + return transitiveAreas; + } + + /** + * Return a query to evaluate the set with all fully qualified section names, containing only the + * sections that match the predicate and have properties attached. This method should return the sections as accurate as possible, + * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage + * does not support key iteration. + * + * @param properties properties to find sections in. + * @param predicate A predicate to determine, which sections should be returned, not {@code null}. + * @return s set with all sections, never {@code null}. + */ + public static Set<String> sections(Map<String, String> properties, final Predicate<String> predicate) { + Set<String> treeSet = new TreeSet<>(); + for (String area : sections(properties)) { + if (predicate.test(area)) { + treeSet.add(area); + } + } + return treeSet; + } + + /** + * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all + * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate as possible, + * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage + * does not support key iteration. + * + * @param properties properties to find transitive sections in. + * @param predicate A predicate to determine, which sections should be returned, not {@code null}. + * @return s set with all transitive sections, never {@code null}. + */ + public static Set<String> transitiveSections(Map<String, String> properties, Predicate<String> predicate) { + Set<String> treeSet = new TreeSet<>(); + for (String area : transitiveSections(properties)) { + if (predicate.test(area)) { + treeSet.add(area); + } + } + return treeSet; + } + + + /** + *Extracts the submap containing only entries with keys + * that are contained in the given sections. Hereby + * the section key is stripped away from the Map of the resulting keys. + * + * @param properties properties to find recursive sections in. + * @param sectionKeys the section keys, not null + * @return the section configuration, with the areaKey stripped away. + */ + public static Map<String, String> sectionsRecursive(Map<String, String> properties, String... sectionKeys) { + return sectionsRecursive(properties, true, sectionKeys); + } + + /** + * Extracts the submap containing only entries with keys + * that are contained in the given section and it's subsections. + * + * @param properties properties to find sections in. + * @param sectionKeys the section keys, not null + * @param stripKeys if set to true, the section key is stripped away fromMap the resulting key. + * @return the section configuration, with the areaKey stripped away. + */ + public static Map<String, String> sectionsRecursive(Map<String, String> properties, boolean stripKeys, String... sectionKeys) { + Map<String, String> result = new HashMap<>(properties.size()); + for (Map.Entry<String, String> en : properties.entrySet()) { + if (isKeyInSection(en.getKey(), false,DEFAULT_AREA_CALCULATOR, sectionKeys)) { + if (stripKeys) { + result.put(stripSectionKeys(en.getKey(), sectionKeys), en.getValue()); + }else { + result.put(en.getKey(), en.getValue()); + } + } + } + return result; + } + + /** + * Strips the section key of the given absolute key, if it is one of the areaKeys passed. + * + * @param key the current key, not null. + * @param areaKeys the areaKeys, not null. + * @return the stripped key, or the original key (if no section was matching). + */ + static String stripSectionKeys(String key, String... areaKeys) { + for (String areaKey : areaKeys) { + if (key.startsWith(areaKey + '.')) { + return key.substring(areaKey.length() + 1); + } + } + return key; + } + + /** + * Creates a ConfigOperator that adds the given items. + * + * @param propertySource source property source that is changed. + * @param items the items to be added/replaced. + * @param override if true, all items existing are overridden by the new ones passed. + * @return the ConfigOperator, never null. + */ + public static ConfigSource addItems(ConfigSource propertySource, final Map<String, String> items, final boolean override) { + return new EnrichedConfigSource(propertySource, items, override); + } + + /** + * Creates an operator that adds items to the instance (existing items will not be overridden). + * + * @param propertySource source property source that is changed. + * @param items the items, not null. + * @return the operator, never null. + */ + public static ConfigSource addItems(ConfigSource propertySource, Map<String, String> items) { + return addItems(propertySource, items, false); + } + + /** + * Creates an operator that replaces the given items. + * + * @param propertySource source property source that is changed. + * @param items the items. + * @return the operator for replacing the items. + */ + public static ConfigSource replaceItems(ConfigSource propertySource, Map<String, String> items) { + return addItems(propertySource, items, true); + } + + /** + * Accesses an empty PropertySource. + * + * @return an empty PropertySource, never null. + */ + public static ConfigSource emptyConfigSource() { + return EMPTY_PROPERTYSOURCE; + } + + /** + * Find all {@link ConfigSource} instances managed by the current + * {@link javax.config.Config} that are assignable to the given type. + * + * @param expression the regular expression to match the source's name. + * @return the list of all {@link ConfigSource} instances matching, never null. + */ + public static Collection<? extends ConfigSource> findPropertySourcesByName(String expression) { + List result = new ArrayList<>(); + for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) { + if (src.getName().matches(expression)) { + result.add(src); + } + } + return result; + } + + /** + * Get a list of all {@link ConfigSource} instances managed by the current + * {@link javax.config.Config} that are assignable to the given type. + * + * @param <T> the type of the property source instances requested + * @param type target type to filter for property sources. + * @return the list of all {@link ConfigSource} instances matching, never null. + */ + public static <T> Collection<T> getPropertySources(Class<T> type) { + List<T> result = new ArrayList<>(); + for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) { + if (type.isAssignableFrom(src.getClass())) { + result.add((T) src); + } + } + return result; + } + + /** + * Get a list of all {@link ConfigSource} instances managed by the current + * {@link javax.config.Config} that are assignable to the given type. + * + * @param <T> the type of the property source instances requested + * @param type target type to filter for property sources. + * @return the list of all {@link ConfigSource} instances matching, never null. + */ + public static <T> T getPropertySource(Class<T> type) { + for (ConfigSource src : ConfigProvider.getConfig().getConfigSources()) { + if (type.isAssignableFrom(src.getClass())) { + return (T) src; + } + } + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java index 76581b7..15e6242 100644 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java @@ -303,7 +303,7 @@ public final class ConfigurationFunctions { if (stripKeys) { return new MappedConfiguration( filtered, - k -> PropertySourceFunctions.stripSectionKeys(k, sectionKeys), + k -> ConfigSourceFunctions.stripSectionKeys(k, sectionKeys), "stripped"); } return filtered; http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java new file mode 100644 index 0000000..c628a95 --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedConfigSource.java @@ -0,0 +1,93 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + +import org.apache.tamaya.base.configsource.ConfigSourceComparator; + +import javax.config.spi.ConfigSource; +import java.util.*; + +/** + * PropertySource, that has values added or overridden. + */ +class EnrichedConfigSource implements ConfigSource { + + private final ConfigSource basePropertySource; + + private final Map<String, String> addedProperties = new HashMap<>(); + + private final boolean overriding; + + /** + * Constructor. + * + * @param propertySource the base property source, not null. + * @param properties the properties to be added. + * @param overriding flag if existing properties are overridden. + */ + EnrichedConfigSource(ConfigSource propertySource, Map<String, String> properties, boolean overriding) { + this.basePropertySource = Objects.requireNonNull(propertySource); + for(Map.Entry<String,String> en:properties.entrySet()){ + this.addedProperties.putAll(properties); + } + this.overriding = overriding; + } + + + @Override + public int getOrdinal() { + return ConfigSourceComparator.getOrdinal(basePropertySource); + } + + @Override + public String getName() { + return basePropertySource.getName(); + } + + @Override + public String getValue(String key) { + if (overriding) { + String val = addedProperties.get(key); + if (val != null) { + return val; + } + return basePropertySource.getValue(key); + } + String val = basePropertySource.getValue(key); + if (val != null) { + return val; + } + return addedProperties.get(key); + + } + + @Override + public Map<String, String> getProperties() { + Map<String, String> allProps = new HashMap<>(); + if (overriding) { + allProps.putAll(basePropertySource.getProperties()); + allProps.putAll(addedProperties); + } else { + allProps.putAll(addedProperties); + allProps.putAll(basePropertySource.getProperties()); + } + return allProps; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java deleted file mode 100644 index c1367b8..0000000 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/EnrichedPropertySource.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - */ -package org.apache.tamaya.functions; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; -import org.apache.tamaya.spisupport.PropertySourceComparator; - -import java.util.*; - -/** - * PropertySource, that has values added or overridden. - */ -class EnrichedPropertySource implements PropertySource { - - private final PropertySource basePropertySource; - - private final Map<String, PropertyValue> addedProperties = new HashMap<>(); - - private final boolean overriding; - - /** - * Constructor. - * - * @param propertySource the base property source, not null. - * @param properties the properties to be added. - * @param overriding flag if existing properties are overridden. - */ - EnrichedPropertySource(PropertySource propertySource, Map<String, String> properties, boolean overriding) { - this.basePropertySource = Objects.requireNonNull(propertySource); - for(Map.Entry<String,String> en:properties.entrySet()){ - this.addedProperties.put(en.getKey(), PropertyValue.of(en.getKey(), en.getValue(), propertySource.getName())); - } - this.overriding = overriding; - } - - - @Override - public int getOrdinal() { - return PropertySourceComparator.getOrdinal(basePropertySource); - } - - @Override - public String getName() { - return basePropertySource.getName(); - } - - @Override - public PropertyValue get(String key) { - if (overriding) { - PropertyValue val = addedProperties.get(key); - if (val != null) { - return val; - } - return basePropertySource.get(key); - } - PropertyValue val = basePropertySource.get(key); - if (val != null) { - return val; - } - return addedProperties.get(key); - - } - - @Override - public Map<String, PropertyValue> getProperties() { - Map<String, PropertyValue> allProps; - if (overriding) { - allProps = new HashMap<>(); - for(PropertyValue val:basePropertySource.getProperties().values()){ - allProps.put(val.getKey(), val); - } - allProps.putAll(addedProperties); - } else { - allProps = new HashMap<>(addedProperties); - for(PropertyValue val:basePropertySource.getProperties().values()){ - allProps.put(val.getKey(), val); - } - } - return allProps; - } - - @Override - public boolean isScannable() { - return basePropertySource.isScannable(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java new file mode 100644 index 0000000..51ccb3b --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredConfigSource.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + + +import org.apache.tamaya.base.configsource.ConfigSourceComparator; + +import javax.config.spi.ConfigSource; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * PropertySource that on the fly filters out part of the key/values of the underlying PropertySource. + */ +class FilteredConfigSource implements ConfigSource { + + private final ConfigSource baseSource; + private final Predicate<String> filter; + + /** + * Creates a new instance + * @param baseSource the underlying PropertySource + * @param filter the filter to be applied. + */ + public FilteredConfigSource(ConfigSource baseSource, Predicate<String> filter){ + this.baseSource = Objects.requireNonNull(baseSource); + this.filter = Objects.requireNonNull(filter); + } + + @Override + public int getOrdinal(){ + return ConfigSourceComparator.getOrdinal(getBaseSource()); + } + + @Override + public String getName() { + return baseSource.getName(); + } + + @Override + public String getValue(String key) { + String val = this.getBaseSource().getValue(key); + if(val!=null && filter.test(key)) { + return val; + } + return null; + } + + @Override + public Map<String, String> getProperties(){ + final Map<String,String> result = new HashMap<>(); + for(Map.Entry<String,String> en: this.getBaseSource().getProperties().entrySet()) { + if (filter.test(en.getKey())) { + result.put(en.getKey(), en.getValue()); + } + } + return result; + } + + protected ConfigSource getBaseSource() { + return baseSource; + } + + @Override + public String toString() { + return "FilteredPropertySource{" + + "baseSource=" + getBaseSource() + + ", filter=" + filter + + '}'; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java deleted file mode 100644 index 133862d..0000000 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/FilteredPropertySource.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ -package org.apache.tamaya.functions; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; -import org.apache.tamaya.spisupport.PropertySourceComparator; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * PropertySource that on the fly filters out part of the key/values of the underlying PropertySource. - */ -class FilteredPropertySource implements PropertySource { - - private final PropertySource baseSource; - private final Predicate<String> filter; - - /** - * Creates a new instance - * @param baseSource the underlying PropertySource - * @param filter the filter to be applied. - */ - public FilteredPropertySource(PropertySource baseSource, Predicate<String> filter){ - this.baseSource = Objects.requireNonNull(baseSource); - this.filter = Objects.requireNonNull(filter); - } - - @Override - public int getOrdinal(){ - return PropertySourceComparator.getOrdinal(getBaseSource()); - } - - @Override - public String getName() { - return baseSource.getName(); - } - - @Override - public PropertyValue get(String key) { - PropertyValue val = this.getBaseSource().get(key); - if(val!=null && filter.test(val.getKey())) { - return val; - } - return null; - } - - @Override - public Map<String, PropertyValue> getProperties(){ - final Map<String,PropertyValue> result = new HashMap<>(); - for(PropertyValue val: this.getBaseSource().getProperties().values()) { - if (filter.test(val.getKey())) { - result.put(val.getKey(), val); - } - } - return result; - } - - @Override - public boolean isScannable() { - return getBaseSource().isScannable(); - } - - @Override - public String toString() { - return "FilteredPropertySource{" + - "baseSource=" + getBaseSource() + - ", filter=" + filter + - '}'; - } - - protected PropertySource getBaseSource() { - return baseSource; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java new file mode 100644 index 0000000..1b3881b --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedConfigSource.java @@ -0,0 +1,109 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + + +import org.apache.tamaya.base.configsource.ConfigSourceComparator; + +import javax.config.spi.ConfigSource; +import java.util.*; + +/** + * PropertySource implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate sections. + */ +class MappedConfigSource implements ConfigSource { + + private static final long serialVersionUID = 8690637705511432083L; + + /** + * The mapping operator. + */ + private final KeyMapper keyMapper; + + /** + * The base configuration. + */ + private final ConfigSource propertySource; + + /** + * Creates a new instance. + * + * @param config the base configuration, not null + * @param keyMapper The mapping operator, not null + */ + public MappedConfigSource(ConfigSource config, KeyMapper keyMapper) { + this.propertySource = Objects.requireNonNull(config); + this.keyMapper = Objects.requireNonNull(keyMapper); + } + + @Override + public int getOrdinal() { + return ConfigSourceComparator.getOrdinal(this.propertySource); + } + + @Override + public String getName() { + return this.propertySource.getName() + "[mapped]"; + } + + @Override + public Map<String, String> getProperties() { + Map<String,String> result = new HashMap<>(); + for (Map.Entry<String,String> en : this.propertySource.getProperties().entrySet()) { + String targetKey = keyMapper.mapKey(en.getKey()); + if (targetKey != null) { + result.put(targetKey, en.getValue()); + } + } + return result; + } + + /** + * <p>Access a property by its key.</p> + * + * <p> + * The key of the property to be returned must be equal to the key + * returned by the mapping operator (key mapper) and not equal + * to the key of the base configuration. + * </p> + * + * @param key the property's key, not {@code null}. + * @return the property value map, where {@code map.get(key) == value}, + * including also any metadata. In case a value is {@code null}, + * simply return {@code null}. + */ + @Override + public String getValue(String key) { + Objects.requireNonNull(key, "Key must be given."); + + String mappedKey = keyMapper.mapKey(key); + String result = null; + + if (mappedKey != null) { + for (Map.Entry<String,String> en : propertySource.getProperties().entrySet()) { + String newKey = keyMapper.mapKey(en.getKey()); + if (mappedKey.equals(newKey)) { + return en.getValue(); + } + } + } + return result; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java deleted file mode 100644 index 7e48f22..0000000 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/MappedPropertySource.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ -package org.apache.tamaya.functions; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; -import org.apache.tamaya.spisupport.PropertySourceComparator; - -import java.util.*; - -/** - * PropertySource implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate sections. - */ -class MappedPropertySource implements PropertySource { - - private static final long serialVersionUID = 8690637705511432083L; - - /** - * The mapping operator. - */ - private final KeyMapper keyMapper; - - /** - * The base configuration. - */ - private final PropertySource propertySource; - - /** - * Creates a new instance. - * - * @param config the base configuration, not null - * @param keyMapper The mapping operator, not null - */ - public MappedPropertySource(PropertySource config, KeyMapper keyMapper) { - this.propertySource = Objects.requireNonNull(config); - this.keyMapper = Objects.requireNonNull(keyMapper); - } - - @Override - public int getOrdinal() { - return PropertySourceComparator.getOrdinal(this.propertySource); - } - - @Override - public String getName() { - return this.propertySource.getName() + "[mapped]"; - } - - @Override - public Map<String, PropertyValue> getProperties() { - Map<String,PropertyValue> result = new HashMap<>(); - for (PropertyValue en : this.propertySource.getProperties().values()) { - String targetKey = keyMapper.mapKey(en.getKey()); - if (targetKey != null) { - result.put(targetKey, PropertyValue.of(targetKey, en.getValue(), getName())); - } - } - return result; - } - - @Override - public boolean isScannable() { - return propertySource.isScannable(); - } - - - /** - * <p>Access a property by its key.</p> - * - * <p> - * The key of the property to be returned must be equal to the key - * returned by the mapping operator (key mapper) and not equal - * to the key of the base configuration. - * </p> - * - * @param key the property's key, not {@code null}. - * @return the property value map, where {@code map.get(key) == value}, - * including also any metadata. In case a value is {@code null}, - * simply return {@code null}. - */ - @Override - public PropertyValue get(String key) { - Objects.requireNonNull(key, "Key must be given."); - - String mappedKey = keyMapper.mapKey(key); - PropertyValue result = null; - - if (mappedKey != null) { - for (PropertyValue property : propertySource.getProperties().values()) { - String newKey = keyMapper.mapKey(property.getKey()); - - if (mappedKey.equals(newKey)) { - String mappedName = getName(); - return property.toBuilder().mapKey(newKey) - .setSource(mappedName).build(); - } - } - } - - return result; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java deleted file mode 100644 index 6f20d6f..0000000 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/PropertySourceFunctions.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * 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. - */ -package org.apache.tamaya.functions; - -import org.apache.tamaya.ConfigurationProvider; -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; - -import java.util.*; - -import static java.lang.System.arraycopy; - -/** - * Accessor that provides useful functions along with configuration. - */ -public final class PropertySourceFunctions { - /** - * Implementation of an empty propertySource. - */ - private static final PropertySource EMPTY_PROPERTYSOURCE = new PropertySource() { - - @Override - public int getOrdinal() { - return 0; - } - - @Override - public String getName() { - return "<empty>"; - } - - @Override - public PropertyValue get(String key) { - return null; - } - - @Override - public Map<String, PropertyValue> getProperties() { - return Collections.emptyMap(); - } - - @Override - public boolean isScannable() { - return true; - } - - @Override - public String toString() { - return "PropertySource<empty>"; - } - }; - - /** - * Private singleton constructor. - */ - private PropertySourceFunctions() { - } - - /** - * Calculates the current section key and compares it to the given key. - * - * @param key the fully qualified entry key, not null - * @param sectionKey the section key, not null - * - * @return true, if the entry is exact in this section - */ - public static boolean isKeyInSection(String key, String sectionKey) { - Objects.requireNonNull(key, "Key must be given."); - Objects.requireNonNull(sectionKey, "Section key must be given."); - - sectionKey = normalizeSectionKey(sectionKey); - - int lastIndex = key.lastIndexOf('.'); - String curAreaKey = lastIndex > 0 ? key.substring(0, lastIndex) : ""; - return curAreaKey.equals(sectionKey); - } - - private static String normalizeKey(String key) { - return key.startsWith(".") ? key.substring(1) - : key; - } - - static String normalizeSectionKey(String sectionKey) { - // Ignore unneeded and trailing dot at the end of the section key - - String normalizedKey = sectionKey.endsWith(".") - ? sectionKey.substring(0, sectionKey.length() - 1) - : sectionKey; - - normalizedKey = sectionKey.startsWith(".") ? sectionKey.length() == 1 ? "" - : normalizedKey.substring(1) - : normalizedKey; - - return normalizedKey; - } - - /** - * Calculates the current section key and compares it to the given section keys. - * - * @param key the fully qualified entry key, not {@code null} - * @param sectionKey the section keys, not {@code null} - * @param moreSectionKeys the more section keys, not {@code null} - * - * @return true, if the entry is in one of the given sections - */ - public static boolean isKeyInSections(String key, String sectionKey, String... moreSectionKeys) { - Objects.requireNonNull(key, "Key must be given."); - Objects.requireNonNull(sectionKey, "At least one section key must be given."); - Objects.requireNonNull(moreSectionKeys, "Additional section keys must not be null."); - - String[] sectionKeys = new String[moreSectionKeys.length + 1]; - sectionKeys[0] = sectionKey; - - if (moreSectionKeys.length > 0) { - arraycopy(moreSectionKeys, 0, sectionKeys, 1, moreSectionKeys.length); - } - - return isKeyInSections(key, sectionKeys); - } - - /** - * Calculates the current section key and compares it to the given section keys. - * - * @param key the fully qualified entry key, not {@code null} - * @param sectionKeys the section keys, not {@code null} - * - * @return true, if the entry is in one of the given sections - */ - public static boolean isKeyInSections(String key, String[] sectionKeys) { - Objects.requireNonNull(key, "Key must be given."); - Objects.requireNonNull(sectionKeys, "Section keys must be given."); - - boolean result = false; - - for (String areaKey : sectionKeys) { - if (areaKey == null) { - continue; - } - - if (isKeyInSection(key, areaKey)) { - result = true; - break; - } - } - - return result; - } - - /** - * Return a query to evaluate the set with all fully qualified section names. This method should return the sections as accurate as possible, - * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage - * does not support key iteration. - * - * @param properties properties to find sections in. - * @return set with all sections, never {@code null}. - */ - public static Set<String> sections(Map<String, String> properties) { - final Set<String> areas = new HashSet<>(); - for (String key : properties.keySet()) { - String normalizedKey = normalizeKey(key); - - int index = normalizedKey.lastIndexOf('.'); - if (index > 0) { - areas.add(normalizedKey.substring(0, index)); - } else { - areas.add("<root>"); - } - } - return areas; - } - - /** - * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all - * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate - * as possible, but may not provide a complete set of sections that are finally accessible, especially when the - * underlying storage does not support key iteration. - * - * @param properties properties to find transitive sections in. - * @return s set with all transitive sections, never {@code null}. - */ - public static Set<String> transitiveSections(Map<String, String> properties) { - final Set<String> transitiveAreas = new HashSet<>(); - for (String section : sections(properties)) { - section = normalizeSectionKey(section); - - int index = section.lastIndexOf('.'); - if (index < 0 && section.isEmpty()) { - transitiveAreas.add("<root>"); - } if (index < 0) { - transitiveAreas.add(section); - } else { - while (index > 0) { - section = section.substring(0, index); - transitiveAreas.add(section); - index = section.lastIndexOf('.'); - } - } - } - return transitiveAreas; - } - - /** - * Return a query to evaluate the set with all fully qualified section names, containing only the - * sections that match the predicate and have properties attached. This method should return the sections as accurate as possible, - * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage - * does not support key iteration. - * - * @param properties properties to find sections in. - * @param predicate A predicate to determine, which sections should be returned, not {@code null}. - * @return s set with all sections, never {@code null}. - */ - public static Set<String> sections(Map<String, String> properties, final Predicate<String> predicate) { - Set<String> treeSet = new TreeSet<>(); - for (String area : sections(properties)) { - if (predicate.test(area)) { - treeSet.add(area); - } - } - return treeSet; - } - - /** - * Return a query to evaluate the set with all fully qualified section names, containing the transitive closure also including all - * subarea names, regardless if properties are accessible or not. This method should return the sections as accurate as possible, - * but may not provide a complete set of sections that are finally accessible, especially when the underlying storage - * does not support key iteration. - * - * @param properties properties to find transitive sections in. - * @param predicate A predicate to determine, which sections should be returned, not {@code null}. - * @return s set with all transitive sections, never {@code null}. - */ - public static Set<String> transitiveSections(Map<String, String> properties, Predicate<String> predicate) { - Set<String> treeSet = new TreeSet<>(); - for (String area : transitiveSections(properties)) { - if (predicate.test(area)) { - treeSet.add(area); - } - } - return treeSet; - } - - - /** - * Creates a ConfigOperator that creates a Configuration containing only keys - * that are contained in the given section (recursive). Hereby - * the section key is stripped away from the Map of the resulting keys. - * - * @param properties properties to find recursive sections in. - * @param sectionKeys the section keys, not null - * @return the section configuration, with the areaKey stripped away. - */ - public static Map<String, String> sectionsRecursive(Map<String, String> properties, String... sectionKeys) { - return sectionRecursive(properties, true, sectionKeys); - } - - /** - * Creates a ConfigOperator that creates a Configuration containing only keys - * that are contained in the given section (recursive). - * - * @param properties properties to find sections in. - * @param sectionKeys the section keys, not null - * @param stripKeys if set to true, the section key is stripped away fromMap the resulting key. - * @return the section configuration, with the areaKey stripped away. - */ - public static Map<String, String> sectionRecursive(Map<String, String> properties, boolean stripKeys, String... sectionKeys) { - Map<String, String> result = new HashMap<>(properties.size()); - if (stripKeys) { - for (Map.Entry<String, String> en : properties.entrySet()) { - if (isKeyInSections(en.getKey(), sectionKeys)) { - result.put(en.getKey(), en.getValue()); - } - } - } else { - for (Map.Entry<String, String> en : properties.entrySet()) { - if (isKeyInSections(en.getKey(), sectionKeys)) { - result.put(stripSectionKeys(en.getKey(), sectionKeys), en.getValue()); - } - } - } - return result; - } - - /** - * Strips the section key of the given absolute key, if it is one of the areaKeys passed. - * - * @param key the current key, not null. - * @param areaKeys the areaKeys, not null. - * @return the stripped key, or the original key (if no section was matching). - */ - static String stripSectionKeys(String key, String... areaKeys) { - for (String areaKey : areaKeys) { - if (key.startsWith(areaKey + '.')) { - return key.substring(areaKey.length() + 1); - } - } - return key; - } - - /** - * Creates a ConfigOperator that adds the given items. - * - * @param propertySource source property source that is changed. - * @param items the items to be added/replaced. - * @param override if true, all items existing are overridden by the new ones passed. - * @return the ConfigOperator, never null. - */ - public static PropertySource addItems(PropertySource propertySource, final Map<String, String> items, final boolean override) { - return new EnrichedPropertySource(propertySource, items, override); - } - - /** - * Creates an operator that adds items to the instance. - * - * @param propertySource source property source that is changed. - * @param items the items, not null. - * @return the operator, never null. - */ - public static PropertySource addItems(PropertySource propertySource, Map<String, String> items) { - return addItems(propertySource, items, false); - } - - /** - * Creates an operator that replaces the given items. - * - * @param propertySource source property source that is changed. - * @param items the items. - * @return the operator for replacing the items. - */ - public static PropertySource replaceItems(PropertySource propertySource, Map<String, String> items) { - return addItems(propertySource, items, true); - } - - /** - * Accesses an empty PropertySource. - * - * @return an empty PropertySource, never null. - */ - public static PropertySource emptyPropertySource() { - return EMPTY_PROPERTYSOURCE; - } - - /** - * Find all {@link PropertySource} instances managed by the current - * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type. - * - * @param expression the regular expression to match the source's name. - * @return the list of all {@link PropertySource} instances matching, never null. - */ - public static Collection<? extends PropertySource> findPropertySourcesByName(String expression) { - List result = new ArrayList<>(); - for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) { - if (src.getName().matches(expression)) { - result.add(src); - } - } - return result; - } - - /** - * Get a list of all {@link PropertySource} instances managed by the current - * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type. - * - * @param <T> the type of the property source instances requested - * @param type target type to filter for property sources. - * @return the list of all {@link PropertySource} instances matching, never null. - */ - public static <T> Collection<T> getPropertySources(Class<T> type) { - List<T> result = new ArrayList<>(); - for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) { - if (type.isAssignableFrom(src.getClass())) { - result.add((T) src); - } - } - return result; - } - - /** - * Get a list of all {@link PropertySource} instances managed by the current - * {@link org.apache.tamaya.spi.ConfigurationContext} that are assignable to the given type. - * - * @param <T> the type of the property source instances requested - * @param type target type to filter for property sources. - * @return the list of all {@link PropertySource} instances matching, never null. - */ - public static <T> T getPropertySource(Class<T> type) { - for (PropertySource src : ConfigurationProvider.getConfigurationContext().getPropertySources()) { - if (type.isAssignableFrom(src.getClass())) { - return (T) src; - } - } - return null; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java new file mode 100644 index 0000000..dd23c66 --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedConfigSource.java @@ -0,0 +1,75 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + +import org.apache.tamaya.base.configsource.ConfigSourceComparator; + +import javax.config.spi.ConfigSource; +import java.util.*; + + +/** + * Property source which filters any key/values dynamically. + */ +class ValueMappedConfigSource implements ConfigSource{ + + private final String name; + private final PropertyMapper valueFilter; + private final ConfigSource source; + + public ValueMappedConfigSource(String name, PropertyMapper valueFilter, ConfigSource current) { + this.name = name!=null?name:"<valueFiltered> -> name="+current.getName()+", valueFilter="+valueFilter.toString(); + this.valueFilter = valueFilter; + this.source = Objects.requireNonNull(current); + } + + @Override + public int getOrdinal() { + return ConfigSourceComparator.getOrdinal(source); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue(String key) { + return this.source.getValue(key); + } + + @Override + public Map<String, String> getProperties() { + Map<String,String> result = new HashMap<>(); + for(Map.Entry<String,String> en: source.getProperties().entrySet()) { + String mappedValue = valueFilter.mapProperty(en.getKey(), en.getValue()); + result.put(en.getKey(), mappedValue); + } + return result; + } + + @Override + public String toString() { + return "ValueMappedConfigSource{" + + "source=" + source.getName() + + ", name='" + name + '\'' + + ", valueFilter=" + valueFilter + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java deleted file mode 100644 index dfb128f..0000000 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/ValueMappedPropertySource.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ -package org.apache.tamaya.functions; - -import org.apache.tamaya.spi.PropertySource; -import org.apache.tamaya.spi.PropertyValue; -import org.apache.tamaya.spisupport.PropertySourceComparator; - -import java.util.*; - - -/** - * Property source which filters any key/values dynamically. - */ -class ValueMappedPropertySource implements PropertySource{ - - private final String name; - private final PropertyMapper valueFilter; - private final PropertySource source; - - public ValueMappedPropertySource(String name, PropertyMapper valueFilter, PropertySource current) { - this.name = name!=null?name:"<valueFiltered> -> name="+current.getName()+", valueFilter="+valueFilter.toString(); - this.valueFilter = valueFilter; - this.source = Objects.requireNonNull(current); - } - - @Override - public int getOrdinal() { - return PropertySourceComparator.getOrdinal(source); - } - - @Override - public String getName() { - return name; - } - - @Override - public PropertyValue get(String key) { - PropertyValue value = this.source.get(key); - if(value!=null) { - return PropertyValue.of(key, valueFilter.mapProperty(key, value.getValue()), getName()); - } - return null; - } - - @Override - public Map<String, PropertyValue> getProperties() { - Map<String,PropertyValue> result = new HashMap<>(); - for(PropertyValue val : source.getProperties().values()) { - String mappedValue = valueFilter.mapProperty(val.getKey(), val.getValue()); - PropertyValue value = val.toBuilder().setValue(mappedValue).build(); - result.put(val.getKey(), value); - } - return result; - } - - @Override - public boolean isScannable() { - return source.isScannable(); - } - - @Override - public String toString() { - return "ValueMappedPropertySource{" + - "source=" + source.getName() + - ", name='" + name + '\'' + - ", valueFilter=" + valueFilter + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java b/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java index bb27ccd..432c5c0 100644 --- a/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java +++ b/modules/functions/src/test/java/org/apache/tamaya/functions/CombinedConfigurationTest.java @@ -20,7 +20,6 @@ package org.apache.tamaya.functions; import org.apache.tamaya.base.DefaultConfigBuilder; import org.apache.tamaya.base.configsource.SimpleConfigSource; -import org.apache.tamaya.spisupport.DefaultConfiguration; import org.assertj.core.api.ThrowableAssert; import org.junit.Test; import org.mockito.Mockito; http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/36b44661/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java b/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java new file mode 100644 index 0000000..06734db --- /dev/null +++ b/modules/functions/src/test/java/org/apache/tamaya/functions/ConfigSourceFunctionsTest.java @@ -0,0 +1,434 @@ +/* + * 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. + */ +package org.apache.tamaya.functions; + +import org.apache.tamaya.base.configsource.SimpleConfigSource; +import org.assertj.core.api.ThrowableAssert; +import org.junit.Test; + +import javax.config.spi.ConfigSource; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.apache.tamaya.functions.ConfigSourceFunctions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.entry; +import static org.junit.Assert.*; + + +public class ConfigSourceFunctionsTest { + + /* + * Tests for isKeyInSection(String, String) + */ + + @Test + public void isKeyInSectionThrowsNPEIfKeyIsNull() { + assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { + @Override + public void call() throws Throwable { + isKeyInSection("a.b.c", null); + } + }).isInstanceOf(NullPointerException.class) + .hasMessage("Section keys must be given."); + } + + @Test + public void isKeyInSectionThrowsNPEIfSectionKeyIsNull() { + assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { + @Override + public void call() throws Throwable { + isKeyInSection(null, "a.b.c"); + } + }).isInstanceOf(NullPointerException.class) + .hasMessage("Key must be given."); + } + + @Test + public void isKeyInSectionForKeyInRootSection() { + String key = "key"; + String sectionKey = ""; + + boolean result = isKeyInSection(key, sectionKey); + + assertThat(result).describedAs("Key '%s' is in root section '%s'") + .isTrue(); + } + + @Test + public void isKeyInSectionForKeyInExplicitRootSection() { + String key = "key"; + String sectionKey = "."; + + boolean result = isKeyInSection(key, sectionKey); + + assertThat(result).describedAs("Key '%s' is in root section '%s'") + .isTrue(); + } + + @Test + public void isKeyInSectionForKeyInSection() throws Exception { + String key = "abc.def.g.h.key"; + String section = "abc.def.g.h"; + + boolean result = isKeyInSection(key, section); + + assertThat(result).describedAs("Key %s is in section %s", key, section) + .isTrue(); + } + + @Test + public void isKeyInSectionForKeyNotInSection() throws Exception { + String key = "abc.def.g.h.i.key"; + String section = "abc.def.g.h"; + + boolean result = isKeyInSection(key, section); + + assertThat(result).describedAs("Key %s is not in section %s", key, section) + .isFalse(); + } + + @Test + public void isKeyInSectionIgnoresTrailingDotAtTheEndOfTheSection() throws Exception { + String key = "abc.def.g.h.key"; + String section = "abc.def.g.h."; + + boolean result = isKeyInSection(key, section); + + assertThat(result).describedAs("Key %s is in section %s", key, section) + .isTrue(); + } + + + /* + * Tests for isKeyInSection(String, String, String...) + */ + + @Test + public void isKeyInSectionsStringStringStringVarargThrowsNPEIfKeyIsNull() { + assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { + @Override + public void call() throws Throwable { + ConfigSourceFunctions.isKeyInSection(null, "a.b.", "a.b", "b.c"); + } + }).isInstanceOf(NullPointerException.class) + .hasMessage("Key must be given."); + } + + @Test + public void isKeyInSectionStringStringStringVarargshrowsNPEIfMoreSectionKeysIsNull() { + // null should not cause any problems + boolean result = isKeyInSection("key", "l.b", (String) null); + + assertThat(result).isFalse(); + } + + @Test + public void isKeyInSectionStringStringStringVaragrsSectioOfKeyIsAtEndOfVarargs() { + String section = "abc.def."; + String key = section + "key"; + + // null should not cause any problems + boolean result = ConfigSourceFunctions.isKeyInSection(key, "l.b", null, "abc", section); + + assertThat(result).describedAs("Key '%s' is in section '%s'.", key, section).isTrue(); + } + + + /* + * Tests for sections(Map<String, String>) + */ + + // null as parameter + + // empty as parameter + + // all keys in root section + + // some keys in packages + + @Test + public void sectionsMapReturnsAllSectionsForGivenKeysInMap() { + HashMap<String, String> kv = new HashMap<>(); + + kv.put("abc.key", "v"); + kv.put("abc.def.key", "v"); + kv.put("a.key", "v"); + kv.put("b.key", "v"); + kv.put("key", "v"); + + Set<String> result = sections(kv); + + assertThat(result).isNotNull() + .isNotEmpty() + .contains("abc", "abc.def", "a", "b", "<root>"); + } + + @Test + public void sectionsMapTreatsLeadingDotAsOptional() { + HashMap<String, String> kv = new HashMap<>(); + + kv.put(".abc.key", "v"); + kv.put(".abc.def.key", "v"); + kv.put(".a.key", "v"); + kv.put(".b.key", "v"); + kv.put(".key", "v"); + + Set<String> result = sections(kv); + + assertThat(result).isNotNull() + .isNotEmpty() + .contains("abc", "abc.def", "a", "b", "<root>"); + } + + /* + * Tests for sections(Map<String, String> , Predicate<String>) + */ + + @Test + public void sectionsMapPredicateFiltersAccordingToFilter() { + HashMap<String, String> kv = new HashMap<>(); + + kv.put(".abc.key", "v"); + kv.put(".abc.def.key", "v"); + kv.put(".a.key", "v"); + kv.put(".b.key", "v"); + kv.put(".key", "v"); + + Set<String> result = sections(kv, new Predicate<String>() { + @Override + public boolean test(String s) { + return !s.startsWith("a"); + } + }); + + assertThat(result).isNotNull() + .isNotEmpty() + .contains("b", "<root>"); + } + + /* + * Tests for transitiveSections(Map<String, String>) + */ + + @Test + public void bla() { + HashMap<String, String> kv = new HashMap<>(); + + kv.put(".abc.key", "v"); + kv.put(".abc.def.key", "v"); + kv.put(".abc.def.ghi.key", "v"); + kv.put(".a.key", "v"); + kv.put(".b.key", "v"); + kv.put(".key", "v"); + + Set<String> result = transitiveSections(kv); + + for (String s : result) { + System.out.println(s); + } + + + assertThat(result).isNotNull() + .isNotEmpty() + .contains("abc", "abc.def", "a", "b", "<root>"); + + + } + + + @Test + public void testIsKeyInSections() throws Exception { + SimpleConfigSource configSource = SimpleConfigSource.builder("test") + .withProperty("a", "1") + .withProperty("a.a.1", "1.1.1") + .withProperty("a.a.2", "1.1.2") + .withProperty("a.b", "1.2") + .withProperty("b", "2") + .build(); + + assertTrue(ConfigSourceFunctions.isKeyInSection("a.1", "a", "b")); + assertTrue(ConfigSourceFunctions.isKeyInSection("a.1", "b", "a")); + assertFalse(ConfigSourceFunctions.isKeyInSection("a.1", "")); + assertFalse(ConfigSourceFunctions.isKeyInSection("a.b.1", "a")); + assertTrue(ConfigSourceFunctions.isKeyInSection("a.b.1", "a.b")); + assertFalse(ConfigSourceFunctions.isKeyInSection("a.b.1", "", "a")); + assertTrue(ConfigSourceFunctions.isKeyInSection("a.b.1", "", "a.b")); + assertFalse(ConfigSourceFunctions.isKeyInSection("c.a", "","c.a")); + assertFalse(ConfigSourceFunctions.isKeyInSection("a.3", "b")); + } + + + @Test + public void testTransitiveSections() throws Exception { + Map<String,String> sections = new HashMap<>(); + sections.put("a.b.c.d.e", "1"); + sections.put("a.x.y", "2"); + sections.put("bb", "2"); + Set<String> transitiveSections = ConfigSourceFunctions.transitiveSections(sections); + assertThat(transitiveSections) + .isNotNull() + .contains("a", "a.b", "a.b.c", "<root>"); + } + + + @Test + public void testSectionsRecursive() throws Exception { + Map<String,String> sections = new HashMap<>(); + sections.put("a.b.c.d.e", "1"); + sections.put("a.x.y", "2"); + sections.put("b.b", "2"); + sections.put("bb", "2"); + Map<String,String> recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"a.b"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(1) + .contains(entry("c.d.e", "1")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"a"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(2) + .contains(entry("b.c.d.e", "1"), entry("x.y", "2")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"b"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(1) + .contains(entry("b", "2")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"a.b"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(1) + .contains(entry("a.b.c.d.e", "1")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"a"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(2) + .contains(entry("a.b.c.d.e", "1"), entry("a.x.y", "2")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, false,"b"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(1) + .contains(entry("b.b", "2")); + recursiveSections = ConfigSourceFunctions.sectionsRecursive(sections, true,"b"); + assertThat(recursiveSections) + .isNotNull() + .hasSize(1) + .contains(entry("b", "2")); + } + + @Test + public void testStripSectionKeys() throws Exception { + String result = ConfigSourceFunctions.stripSectionKeys("a.b.c", new String[]{ "a.b", "a"}); + assertThat(result) + .isNotNull().isEqualTo("c"); + result = ConfigSourceFunctions.stripSectionKeys("a", new String[]{ "a"}); + assertThat(result) + .isNotNull().isEqualTo("a"); + result = ConfigSourceFunctions.stripSectionKeys("foo.bar", new String[]{ ""}); + assertThat(result) + .isNotNull().isEqualTo("foo.bar"); + } + + @Test + public void testAddItems_Override_Default() throws Exception { + ConfigSource cs = SimpleConfigSource.builder("test") + .withProperty("a", "1") + .withProperty("b", "2") + .build(); + Map<String, String> additions = new HashMap<>(); + additions.put("b", "2-added"); + additions.put("c", "3"); + ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions); + assertNotNull(configSource); + assertThat(configSource.getPropertyNames()) + .isNotNull() + .contains("a", "b", "c"); + assertThat(configSource.getProperties()) + .isNotNull() + .contains(entry("a", "1"), entry("b", "2"), entry("c", "3")); + } + + @Test + public void testAddItemsOverride_Explicit() throws Exception { + ConfigSource cs = SimpleConfigSource.builder("test") + .withProperty("a", "1") + .withProperty("b", "2") + .build(); + Map<String, String> additions = new HashMap<>(); + additions.put("b", "2-added"); + additions.put("c", "3"); + ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions, true); + assertNotNull(configSource); + assertThat(configSource.getPropertyNames()) + .isNotNull() + .contains("a", "b", "c"); + assertThat(configSource.getProperties()) + .isNotNull() + .contains(entry("a", "1"), entry("b", "2-added"), entry("c", "3")); + } + + @Test + public void testAddItemsOverride_False() throws Exception { + ConfigSource cs = SimpleConfigSource.builder("test") + .withProperty("a", "1") + .withProperty("b", "2") + .build(); + Map<String, String> additions = new HashMap<>(); + additions.put("b", "2-added"); + additions.put("c", "3"); + ConfigSource configSource = ConfigSourceFunctions.addItems(cs, additions, false); + assertNotNull(configSource); + assertThat(configSource.getPropertyNames()) + .isNotNull() + .contains("a", "b", "c"); + assertThat(configSource.getProperties()) + .isNotNull() + .contains(entry("a", "1"), entry("b", "2"), entry("c", "3")); + } + + @Test + public void testReplaceItems() throws Exception { + ConfigSource cs = SimpleConfigSource.builder("test") + .withProperty("a", "1") + .withProperty("b", "2") + .build(); + Map<String, String> replacements = new HashMap<>(); + replacements.put("b", "2-added"); + replacements.put("c", "3"); + ConfigSource configSource = ConfigSourceFunctions.replaceItems(cs, replacements); + assertNotNull(configSource); + assertThat(configSource.getPropertyNames()) + .isNotNull() + .contains("a", "b", "c"); + assertThat(configSource.getProperties()) + .isNotNull() + .contains(entry("a", "1"), entry("b", "2-added"), entry("c", "3")); + } + + @Test + public void testEmptyPropertySource() throws Exception { + ConfigSource ps = ConfigSourceFunctions.emptyConfigSource(); + assertThat(ps).isNotNull(); + assertNotNull(ps.getProperties()); + assertTrue(ps.getProperties().isEmpty()); + assertEquals(ps.getName(), "<empty>" ); + } +} \ No newline at end of file
