Reworked format API.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/1e871d87 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/1e871d87 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/1e871d87 Branch: refs/heads/master Commit: 1e871d87a02458c84e9798b37bdaf7237eab65be Parents: 120fbd4 Author: anatole <anat...@apache.org> Authored: Thu Feb 12 22:23:02 2015 +0100 Committer: anatole <anat...@apache.org> Committed: Thu Feb 12 22:32:23 2015 +0100 ---------------------------------------------------------------------- ...hBasedMultiFormatPropertySourceProvider.java | 24 +--- .../BaseSimpleFormatPropertySourceProvider.java | 35 +---- .../tamaya/format/ConfigurationDataBuilder.java | 140 +++++++++++++++++++ .../tamaya/format/ConfigurationFormat.java | 58 ++------ .../tamaya/format/IniConfigurationFormat.java | 23 +-- .../apache/tamaya/format/PropertiesFormat.java | 15 +- .../tamaya/format/PropertiesXmlFormat.java | 16 +-- 7 files changed, 172 insertions(+), 139 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/BasePathBasedMultiFormatPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/BasePathBasedMultiFormatPropertySourceProvider.java b/modules/formats/src/main/java/org/apache/tamaya/format/BasePathBasedMultiFormatPropertySourceProvider.java index ed59f39..cb60d6e 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/BasePathBasedMultiFormatPropertySourceProvider.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/BasePathBasedMultiFormatPropertySourceProvider.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.logging.Level; @@ -89,14 +88,10 @@ public abstract class BasePathBasedMultiFormatPropertySourceProvider implements /** * Method to create a {@link org.apache.tamaya.spi.PropertySource} based on the given entries read. * - * @param entryTypeName the entry type of the entries read, not null. - * @param entries the entries read by the {@link org.apache.tamaya.format.ConfigurationFormat} - * @param formatUsed the format instance used to read the entries. + * @param data the configuration data, not null. * @return the {@link org.apache.tamaya.spi.PropertySource} instance ready to be registered. - * @see org.apache.tamaya.format.ConfigurationFormat#getEntryTypes() */ - protected abstract PropertySource getPropertySource(String entryTypeName, Map<String, String> entries, - ConfigurationFormat formatUsed); + protected abstract Collection<PropertySource> getPropertySources(ConfigurationData data); /** * This method does dynamically resolve the paths using the current ClassLoader set. If no ClassLoader was @@ -107,23 +102,16 @@ public abstract class BasePathBasedMultiFormatPropertySourceProvider implements */ @Override public Collection<PropertySource> getPropertySources() { + ResourceResolver resourceResolver = ServiceContext.getInstance().getService(ResourceResolver.class).get(); List<PropertySource> propertySources = new ArrayList<>(); paths.forEach((path) -> { - for (URL res : ServiceContext.getInstance().getService(ResourceResolver.class).get().getResources( + for (URL res : resourceResolver.getResources( this.classLoader.orElse(Thread.currentThread().getContextClassLoader()), path)) { try { for (ConfigurationFormat format : configFormats) { - Map<String, Map<String, String>> entries = format.readConfiguration(res); - for (Map.Entry<String, Map<String, String>> en : entries.entrySet()) { - PropertySource ps = getPropertySource(en.getKey(), en.getValue(), format); - if (ps != null) { - propertySources.add(ps); - } else { - LOG.info(() -> "Config Entries read ignored by PropertySourceFactory: format=" + format + - ", entryType=" + en.getKey()); - } - } + ConfigurationData entries = format.readConfiguration(res); + propertySources.addAll(getPropertySources(entries)); } } catch (Exception e) { LOG.log(Level.WARNING, "Failed to add resource based config: " + res, e); http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/BaseSimpleFormatPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/BaseSimpleFormatPropertySourceProvider.java b/modules/formats/src/main/java/org/apache/tamaya/format/BaseSimpleFormatPropertySourceProvider.java index 1fe08c2..64afdfe 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/BaseSimpleFormatPropertySourceProvider.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/BaseSimpleFormatPropertySourceProvider.java @@ -64,40 +64,9 @@ public abstract class BaseSimpleFormatPropertySourceProvider implements Property /** * Method to create a {@link org.apache.tamaya.spi.PropertySource} based on the given entries read. * - * @param entryTypeName the entry type of the entries read, not null. - * @param entries the entries read by the {@link ConfigurationFormat} - * @param formatUsed the format instance used to read the entries. + * @param configData the config data read. * @return the {@link org.apache.tamaya.spi.PropertySource} instance ready to be registered. - * @see ConfigurationFormat#getEntryTypes() */ - protected abstract PropertySource getPropertySource(String entryTypeName, Map<String, String> entries, - ConfigurationFormat formatUsed); - - /** - * This method does dynamically resolve the paths using the current ClassLoader set. If no ClassLoader was - * explcitly set during creation the current Thread context ClassLoader is used. If none of the supported - * formats is able to parse a resource a WARNING log is written. - * - * @return the PropertySources successfully read - */ - @Override - public Collection<PropertySource> getPropertySources() { - List<PropertySource> propertySources = new ArrayList<>(); - try { - Map<String, Map<String, String>> entries = configFormat.readConfiguration(resource); - for (Map.Entry<String, Map<String, String>> en : entries.entrySet()) { - PropertySource ps = getPropertySource(en.getKey(), en.getValue(), configFormat); - if (ps != null) { - propertySources.add(ps); - } else { - LOG.info(() -> "Config Entries read ignored by PropertySourceFactory: format=" + configFormat + - ", entryType=" + en.getKey()); - } - } - } catch (Exception e) { - LOG.log(Level.WARNING, "Failed to add resource based config: " + resource, e); - } - return propertySources; - } + protected abstract Collection<PropertySource> createPropertySourcea(ConfigurationData configData); } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationDataBuilder.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationDataBuilder.java b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationDataBuilder.java new file mode 100644 index 0000000..556d3ed --- /dev/null +++ b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationDataBuilder.java @@ -0,0 +1,140 @@ +/* + * 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.format; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + + +/** + * Builder for creating {@link org.apache.tamaya.format.ConfigurationData} instances. This class is not thread-safe. + */ +public final class ConfigurationDataBuilder { + + /** The format instance used to read this instance. */ + ConfigurationFormat format; + /** The resource read. */ + URL resource; + /** The data read. */ + Map<String,Map<String,String>> data = new HashMap<>(); + + /** + * Private constructor. + * @param resource the configuration resource URL, not null. + * @param format the format that read this data, not null. + */ + private ConfigurationDataBuilder(URL resource, ConfigurationFormat format){ + this.format = Objects.requireNonNull(format); + this.resource = Objects.requireNonNull(resource); + } + + /** + * Creates a new instance. + * @param resource the configuration resource URL, not null. + * @param format the format that read this data, not null. + */ + public static ConfigurationDataBuilder of(URL resource, ConfigurationFormat format){ + return new ConfigurationDataBuilder(resource, format); + } + + /** + * Creates a new instance. + * @param data an existing COnfigurationData instances used to initialize the builder. + */ + public static ConfigurationDataBuilder of(ConfigurationData data){ + ConfigurationDataBuilder b = new ConfigurationDataBuilder(data.getResource(), data.getFormat()); + b.data.putAll(data.getData()); + return b; + } + + /** + * Adds (empty) sections,if they are not yet existing. Already existing sections will not be touched. + * @param sections the new sections to add. + * @return the builder for chaining. + */ + public ConfigurationDataBuilder addSections(String... sections){ + for(String section:sections) { + this.data.computeIfAbsent(section, (k) -> new HashMap<>()); + } + return this; + } + + /** + * Adds a single entry to a target section. + * @param section the target section (will be created if not existing). + * @param key the entry's key + * @param value the entry's value + * @return the builder for chaining. + */ + public ConfigurationDataBuilder addProperty(String section, String key, String value){ + Map<String,String> map = this.data.computeIfAbsent(section, (k) -> new HashMap<>()); + map.put(key, value); + return this; + } + + /** + * Adds a single entry to the <i>default</i> section. + * @param key the entry's key + * @param value the entry's value + * @return the builder for chaining. + */ + public ConfigurationDataBuilder addProperty(String key, String value){ + return addProperty(ConfigurationData.DEFAULT_SECTION_NAME, key, value); + } + + /** + * Adds the given entries to the given section, all existing values will be overridden. + * @param section the target section (will be created if not existing). + * @param properties the entry's data + * @return the builder for chaining. + */ + public ConfigurationDataBuilder addProperties(String section, Map<String,String> properties){ + Map<String,String> map = this.data.computeIfAbsent(section, (k) -> new HashMap<>()); + map.putAll(properties); + return this; + } + + /** + * Adds the given entries to the <i>default</i> section, all existing values will be overridden. + * @param properties the entry's data + * @return the builder for chaining. + */ + public ConfigurationDataBuilder addProperties( Map<String,String> properties){ + return addProperties(ConfigurationData.DEFAULT_SECTION_NAME, properties); + } + + /** + * Builds a new {@link org.apache.tamaya.format.ConfigurationData} instance. + * @return a new {@link org.apache.tamaya.format.ConfigurationData} instance, not null. + */ + public ConfigurationData build(){ + return new ConfigurationData(this); + } + + @Override + public String toString() { + return "ConfigurationDataBuilder{" + + "format=" + format + + ", data=" + data + + ", resource=" + resource.toString() + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java index 53c171c..e35517b 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/ConfigurationFormat.java @@ -19,56 +19,25 @@ package org.apache.tamaya.format; import java.net.URL; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; /** * Implementations current this class encapsulate the mechanism how to read a * resource including interpreting the format correctly (e.g. xml vs. - * properties). In most cases file only contains entries of the same priority, which would then - * result in only one {@link org.apache.tamaya.spi.PropertySource}. Complex file formats, hoiwever, may contain entries - * of different priorities. In this cases, each ordinal type found must be returned as a separate - * {@link org.apache.tamaya.spi.PropertySource} instance. + * properties vs. ini). In most cases file only contains entries of the same priority, which would then + * result in only one {@link org.apache.tamaya.spi.PropertySource}. Complex file formats, however, may contain entries + * of different priorities. In this cases, each ordinal type found typically is returned as a separate section so the + * consuming {@link org.apache.tamaya.spi.PropertySourceProvider} implementation can distribute the different part to + * individual {@link org.apache.tamaya.spi.PropertySource}s.<p> + * <h3>Implementation Requirements</h3> + * Implementations of this type must be + * <ul> + * <li>thread-safe</li> + * </ul> */ +@FunctionalInterface public interface ConfigurationFormat { /** - * The default entry type returned if a format implementation does not support any explicit entry types. - */ - public static final String DEFAULT_ENTRY_TYPE = "default"; - public static final Set<String> DEFAULT_ENTRY_TYPE_SET = initDefaultSet(); - public static final String DYNAMIC_ENTRY_TYPE = "<dynamic>"; - - static Set<String> initDefaultSet(){ - Set<String> set = new HashSet<>(); - set.add(DEFAULT_ENTRY_TYPE); - return Collections.unmodifiableSet(set); - }; - - /** - * Access the different entry types a format supports. Entries of the same entry type hereby share the same - * configuration priority. The reason for this concept is that a configuration format can produce different - * types of properties, e.g. default properties, named properties, overriding ones as illustrated below: - * <pre> - * [defaults] - * a.b.c=alphabet - * foo.bar=any - * - * [staged:development] - * a.b.myEntry=1234 - * - * [management-overrides] - * a.b.d=Alphabet - * </pre> - * If just using ordinary property files, of course, only one entry type is returned, called 'default'. - * #see DEFAULT_ENTRY_TYPE - * @return the set of supported entry types, never null and never empty. - */ - public Set<String> getEntryTypes(); - - /** * Reads a list {@link org.apache.tamaya.spi.PropertySource} instances from a resource, using this format. * If the configuration format only contains entries of one ordinal type, normally only one single * instance of PropertySource is returned. Nevertheless custom formats may contain different sections or parts, @@ -78,10 +47,9 @@ public interface ConfigurationFormat { * * @param url the url to read the configuration data from (could be a file, a remote location, a classpath * resource or something else. - * @return the corresponding {@link java.util.Map} instances of properties read, never {@code null}. Each - * {@link java.util.Map} instance hereby is provided using a type key. + * @return the corresponding {@link ConfigurationData} containing sections/properties read, never {@code null}. * @throws org.apache.tamaya.ConfigException if parsing of the input fails. */ - Map<String, Map<String,String>> readConfiguration(URL url); + ConfigurationData readConfiguration(URL url); } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/IniConfigurationFormat.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/IniConfigurationFormat.java b/modules/formats/src/main/java/org/apache/tamaya/format/IniConfigurationFormat.java index cb73c1e..4e0efa9 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/IniConfigurationFormat.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/IniConfigurationFormat.java @@ -24,12 +24,9 @@ import org.apache.commons.configuration.SubnodeConfiguration; import org.apache.tamaya.ConfigException; import java.net.URL; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; -import java.util.Set; /** * Implements a ini file format based on the APache Commons @@ -37,21 +34,9 @@ import java.util.Set; */ public class IniConfigurationFormat implements ConfigurationFormat{ - private Set<String> entryTypes = new HashSet<>(); - - public IniConfigurationFormat(){ - entryTypes.add(ConfigurationFormat.DYNAMIC_ENTRY_TYPE); - entryTypes = Collections.unmodifiableSet(entryTypes); - } - - @Override - public Set<String> getEntryTypes() { - return entryTypes; - } - @Override - public Map<String, Map<String, String>> readConfiguration(URL url) { - Map<String, Map<String, String>> result = new HashMap<>(); + public ConfigurationData readConfiguration(URL url) { + ConfigurationDataBuilder builder = ConfigurationDataBuilder.of(url, this); try { HierarchicalINIConfiguration commonIniConfiguration = new HierarchicalINIConfiguration(url); for(String section:commonIniConfiguration.getSections()){ @@ -62,11 +47,11 @@ public class IniConfigurationFormat implements ConfigurationFormat{ String key = keyIter.next(); properties.put(key, sectionConfig.getString(key)); } - result.put(section, properties); + builder.addProperties(section, properties); } - return result; } catch (ConfigurationException e) { throw new ConfigException("Failed to parse ini-file format from " + url, e); } + return builder.build(); } } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java index 48a5288..62b6a4e 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesFormat.java @@ -21,11 +21,9 @@ package org.apache.tamaya.format; import java.io.InputStream; import java.net.URL; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Properties; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -40,28 +38,21 @@ public class PropertiesFormat implements ConfigurationFormat { */ private final static Logger LOG = Logger.getLogger(PropertiesFormat.class.getName()); - @Override - public Set<String> getEntryTypes() { - Set<String> set = new HashSet<>(); - set.add(ConfigurationFormat.DEFAULT_ENTRY_TYPE); - return set; - } @SuppressWarnings("unchecked") @Override - public Map<String, Map<String, String>> readConfiguration(URL url) { + public ConfigurationData readConfiguration(URL url) { Objects.requireNonNull(url); - Map<String, Map<String, String>> result = new HashMap<>(); try (InputStream is = url.openStream()) { if (is != null) { final Properties p = new Properties(); p.load(is); - result.put(ConfigurationFormat.DEFAULT_ENTRY_TYPE, Map.class.cast(p)); + return ConfigurationDataBuilder.of(url, this).addProperties( Map.class.cast(p)).build(); } } catch (Exception e) { LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + url); } - return result; + return ConfigurationDataBuilder.of(url, this).build(); } } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/1e871d87/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java ---------------------------------------------------------------------- diff --git a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java index 4ec0898..893ad80 100644 --- a/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java +++ b/modules/formats/src/main/java/org/apache/tamaya/format/PropertiesXmlFormat.java @@ -36,29 +36,21 @@ public class PropertiesXmlFormat implements ConfigurationFormat { */ private final static Logger LOG = Logger.getLogger(PropertiesXmlFormat.class.getName()); - @Override - public Set<String> getEntryTypes() { - Set<String> set = new HashSet<>(); - set.add(ConfigurationFormat.DEFAULT_ENTRY_TYPE); - return set; - } - @SuppressWarnings("unchecked") @Override - public Map<String, Map<String, String>> readConfiguration(URL url) { + public ConfigurationData readConfiguration(URL url) { Objects.requireNonNull(url); - Map<String, Map<String, String>> result = new HashMap<>(); try (InputStream is = url.openStream()) { if (is != null) { final Properties p = new Properties(); - p.loadFromXML(is); - result.put(ConfigurationFormat.DEFAULT_ENTRY_TYPE, Map.class.cast(p)); + p.load(is); + return ConfigurationDataBuilder.of(url, this).addProperties( Map.class.cast(p)).build(); } } catch (Exception e) { LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + url); } - return result; + return ConfigurationDataBuilder.of(url, this).build(); } }