You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by st...@apache.org on 2014/12/27 14:58:00 UTC
[16/34] incubator-tamaya git commit: first step: move all sources to
a 'dormant' directory
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationBuilder.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationBuilder.java
new file mode 100644
index 0000000..f8b1c95
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationBuilder.java
@@ -0,0 +1,374 @@
+/*
+* 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.core.config;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertySource;
+import org.apache.tamaya.core.properties.AggregationPolicy;
+import org.apache.tamaya.core.properties.PropertySourceBuilder;
+
+/**
+* Builder for assembling non trivial {@link org.apache.tamaya.Configuration} instances.
+*/
+public final class ConfigurationBuilder {
+
+ /**
+ * The final meta info to be used, or null, if a default should be generated.
+ */
+ private PropertySourceBuilder builderDelegate;
+
+ /**
+ * Private singleton constructor.
+ */
+ private ConfigurationBuilder(String name) {
+ this.builderDelegate = PropertySourceBuilder.of(name);
+ }
+
+ /**
+ * Private singleton constructor.
+ */
+ private ConfigurationBuilder(String name, PropertySource source) {
+ this.builderDelegate = PropertySourceBuilder.of(name, source);
+ }
+
+ /**
+ * Private singleton constructor.
+ */
+ private ConfigurationBuilder(PropertySource source) {
+ this.builderDelegate = PropertySourceBuilder.of(source);
+ }
+
+
+ /**
+ * Creates a new builder instance.
+ *
+ * @param provider the base provider to be used, not null.
+ * @return a new builder instance, never null.
+ */
+ public static ConfigurationBuilder of(PropertySource provider) {
+ return new ConfigurationBuilder(provider);
+ }
+
+ /**
+ * Creates a new builder instance.
+ *
+ * @param name the provider name, not null.
+ * @return a new builder instance, never null.
+ */
+ public static ConfigurationBuilder of(String name) {
+ return new ConfigurationBuilder(Objects.requireNonNull(name));
+ }
+
+ /**
+ * Creates a new builder instance.
+ *
+ * @return a new builder instance, never null.
+ */
+ public static ConfigurationBuilder of() {
+ return new ConfigurationBuilder("<noname>");
+ }
+
+
+
+
+ /**
+ * Sets the aggregation policy to be used, when adding additional property sets. The policy will
+ * be active a slong as the builder is used or it is reset to another keys.
+ *
+ * @param aggregationPolicy the aggregation policy, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder withAggregationPolicy(AggregationPolicy aggregationPolicy) {
+ this.builderDelegate.withAggregationPolicy(aggregationPolicy);
+ return this;
+ }
+
+ /**
+ * Sets the meta info to be used for the next operation.
+ *
+ * @param name the name, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder withName(String name) {
+ this.builderDelegate.withName(name);
+ return this;
+ }
+
+ /**
+ * Adds the given providers with the current active {@link AggregationPolicy}. By
+ * default {@link AggregationPolicy#OVERRIDE} is used.
+ * @see #withAggregationPolicy(AggregationPolicy)
+ * @param providers providers to be added, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addProviders(PropertySource... providers) {
+ this.builderDelegate.addProviders(providers);
+ return this;
+ }
+
+ /**
+ * Adds the given providers with the current active {@link AggregationPolicy}. By
+ * default {@link AggregationPolicy#OVERRIDE} is used.
+ * @see #withAggregationPolicy(AggregationPolicy)
+ * @param providers providers to be added, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addProviders(List<PropertySource> providers) {
+ this.builderDelegate.addProviders(providers);
+ return this;
+ }
+
+
+ /**
+ * Creates a new {@link org.apache.tamaya.PropertySource} using the given command line arguments and adds it
+ * using the current aggregation policy in place.
+ *
+ * @param args the command line arguments, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addArgs(String... args) {
+ this.builderDelegate.addArgs(args);
+ return this;
+ }
+
+ /**
+ * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according path resources. The effective resources read
+ * hereby are determined by the {@code PathResolverService} configured into the {@code Bootstrap} SPI.
+ * Properties read are aggregated using the current aggregation policy active.
+ *
+ * @param paths the paths to be resolved by the {@code PathResolverService} , not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addPaths(String... paths) {
+ this.builderDelegate.addPaths(paths);
+ return this;
+ }
+
+
+ /**
+ * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according path resources. The effective resources read
+ * hereby are determined by the {@code PathResolverService} configured into the {@code Bootstrap} SPI.
+ * Properties read are aggregated using the current aggregation policy active.
+ *
+ * @param paths the paths to be resolved by the {@code PathResolverService} , not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addPaths(List<String> paths) {
+ this.builderDelegate.addPaths(paths);
+ return this;
+ }
+
+ /**
+ * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according URL resources.
+ * Properties read are aggregated using the current aggregation policy active.
+ *
+ * @param urls the urls to be read, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addURLs(URL... urls) {
+ this.builderDelegate.addURLs(urls);
+ return this;
+ }
+
+ /**
+ * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according URL resources.
+ * Properties read are aggregated using the current aggregation policy active.
+ *
+ * @param urls the urls to be read, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addURLs(List<URL> urls) {
+ this.builderDelegate.addURLs(urls);
+ return this;
+ }
+
+
+ /**
+ * Creates a new read-only {@link org.apache.tamaya.PropertySource} based on the given map.
+ * Properties read are aggregated using the current aggregation policy active.
+ *
+ * @param map the map to be added, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addMap(Map<String, String> map) {
+ this.builderDelegate.addMap(map);
+ return this;
+ }
+
+
+ /**
+ * Add the current environment properties. Aggregation is based on the current {@link AggregationPolicy} acvtive.
+ *
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addEnvironmentProperties() {
+ this.builderDelegate.addEnvironmentProperties();
+ return this;
+ }
+
+ /**
+ * Add the current system properties. Aggregation is based on the current {@link AggregationPolicy} acvtive.
+ *
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder addSystemProperties() {
+ this.builderDelegate.addSystemProperties();
+ return this;
+ }
+
+ /**
+ * Adds the given {@link org.apache.tamaya.PropertySource} instances using the current {@link AggregationPolicy}
+ * active.
+ *
+ * @param providers the maps to be included, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder aggregate(PropertySource... providers) {
+ this.builderDelegate.aggregate(providers);
+ return this;
+ }
+
+
+ /**
+ * Adds the given {@link org.apache.tamaya.PropertySource} instances using the current {@link AggregationPolicy}
+ * active.
+ *
+ * @param providers the maps to be included, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder aggregate(List<PropertySource> providers) {
+ this.builderDelegate.aggregate(providers);
+ return this;
+ }
+
+
+ /**
+ * Intersetcs the current properties with the given {@link org.apache.tamaya.PropertySource} instance.
+ *
+ * @param providers the maps to be intersected, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder intersect(PropertySource... providers) {
+ this.builderDelegate.intersect(providers);
+ return this;
+ }
+
+
+ /**
+ * Subtracts with the given {@link org.apache.tamaya.PropertySource} instance from the current properties.
+ *
+ * @param providers the maps to be subtracted, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigurationBuilder subtract(PropertySource... providers) {
+ this.builderDelegate.subtract(providers);
+ return this;
+ }
+
+
+ /**
+ * Filters the current properties based on the given predicate..
+ *
+ * @param filter the filter to be applied, not null.
+ * @return the new filtering instance.
+ */
+ public ConfigurationBuilder filter(Predicate<String> filter) {
+ this.builderDelegate.filter(filter);
+ return this;
+ }
+
+ /**
+ * Filters the current {@link org.apache.tamaya.Configuration} with the given valueFilter.
+ * @param valueFilter the value filter, not null.
+ * @return the (dynamically) filtered source instance, never null.
+ */
+ public ConfigurationBuilder filterValues(BiFunction<String, String, String> valueFilter){
+ this.builderDelegate.filterValues(valueFilter);
+ return this;
+ }
+
+ /**
+ * Creates a new contextual {@link org.apache.tamaya.PropertySource}. Contextual maps delegate to different instances current PropertyMap depending
+ * on the keys returned fromMap the isolationP
+ *
+ * @param mapSupplier the supplier creating new provider instances
+ * @param isolationKeySupplier the supplier providing contextual keys based on the current environment.
+ */
+ public ConfigurationBuilder addContextual(Supplier<PropertySource> mapSupplier,
+ Supplier<String> isolationKeySupplier) {
+ this.builderDelegate.addContextual(mapSupplier, isolationKeySupplier);
+ return this;
+ }
+
+ /**
+ * Replaces all keys in the current provider by the given map.
+ *
+ * @param replacementMap the map instance, that will replace all corresponding entries in {@code mainMap}, not null.
+ * @return the new delegating instance.
+ */
+ public ConfigurationBuilder replace(Map<String, String> replacementMap) {
+ this.builderDelegate.replace(replacementMap);
+ return this;
+ }
+
+ /**
+ * Build a new property provider based on the input.
+ * @return a new property provider, or null.
+ */
+ public PropertySource buildPropertySource(){
+ return this.builderDelegate.build();
+ }
+
+ /**
+ * Build a new property provider based on the input.
+ * @return a new property provider, or null.
+ */
+ public Configuration build(){
+ return this.buildPropertySource().toConfiguration();
+ }
+
+ /**
+ * Creates a {@link org.apache.tamaya.PropertySource} instance that is serializable and immutable,
+ * so it can be sent over a network connection.
+ *
+ * @return the freezed instance, never null.
+ */
+ public PropertySource buildFreezedPropertySource() {
+ return this.builderDelegate.buildFrozen();
+ }
+
+ /**
+ * Creates a {@link org.apache.tamaya.PropertySource} instance that is serializable and immutable,
+ * so it can be sent over a network connection.
+ *
+ * @return the freezed instance, never null.
+ */
+ public Configuration buildFreezed() {
+ return FreezedConfiguration.of(this.buildFreezedPropertySource().toConfiguration());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationFormat.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationFormat.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationFormat.java
new file mode 100644
index 0000000..8feaf6a
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigurationFormat.java
@@ -0,0 +1,111 @@
+/*
+ * 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.core.config;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.core.spi.ConfigurationFormatSpi;
+import org.apache.tamaya.spi.ServiceContext;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Implementations current this class encapsulate the mechanism how to read a
+ * resource URI including interpreting the format correctly (e.g. xml vs.
+ * properties).
+ */
+public interface ConfigurationFormat{
+
+ /**
+ * Returns a unique identifier that identifies each format.
+ *
+ * @return the unique format id, mever null.
+ */
+ public String getFormatName();
+
+ /**
+ * Check if the given {@link java.net.URI} and path xpression qualify that this format should be
+ * able to read them, e.g. checking for compatible file endings.
+ *
+ * @param resource the configuration location, not null
+ * @return {@code true} if the given resource is in a format supported by
+ * this instance.
+ */
+ boolean isAccepted(Resource resource);
+
+ /**
+ * Reads a {@link org.apache.tamaya.PropertySource} fromMap the given URI, using this format.
+ *
+ * @param resource the configuration location, not null
+ * @return the corresponding {@link java.util.Map}, never {@code null}.
+ */
+ Map<String,String> readConfiguration(Resource resource);
+
+ /**
+ * Access a {@link ConfigurationFormat}.
+ *
+ * @param formatName the format name
+ * @return the corresponding {@link ConfigurationFormat}, or {@code null}, if
+ * not available for the given environment.
+ */
+ public static ConfigurationFormat of(String formatName){
+ return ServiceContext.getInstance().getSingleton(ConfigurationFormatSpi.class).getFormat(formatName);
+ }
+
+ /**
+ * Get a collection current the keys current the registered {@link ConfigurationFormat} instances.
+ *
+ * @return a collection current the keys current the registered {@link ConfigurationFormat} instances.
+ */
+ public static Collection<String> getFormatNames(){
+ return ServiceContext.getInstance().getSingleton(ConfigurationFormatSpi.class).getFormatNames();
+ }
+
+ /**
+ * Evaluate the matching format for a given resource.
+ *
+ * @param resource The resource
+ * @return a matching configuration format, or {@code null} if no matching format could be determined.
+ */
+ public static ConfigurationFormat from(Resource resource){
+ return ServiceContext.getInstance().getSingleton(ConfigurationFormatSpi.class).getFormat(resource);
+
+ }
+
+ /**
+ * Get an instance for reading configuration fromMap a {@code .properties} file,
+ * as defined by {@link java.util.Properties#load(java.io.InputStream)}.
+ *
+ * @return a format instance for reading configuration fromMap a {@code .properties} file, never null.
+ */
+ public static ConfigurationFormat getPropertiesFormat(){
+ return ServiceContext.getInstance().getSingleton(ConfigurationFormatSpi.class).getPropertiesFormat();
+ }
+
+ /**
+ * Get an instance for reading configuration fromMap a {@code .xml} properties file,
+ * as defined by {@link java.util.Properties#loadFromXML(java.io.InputStream)}.
+ *
+ * @return a format instance for reading configuration fromMap a {@code .xml} properties file, never null.
+ */
+ public static ConfigurationFormat getXmlPropertiesFormat(){
+ return ServiceContext.getInstance().getSingleton(ConfigurationFormatSpi.class).getXmlPropertiesFormat();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java
new file mode 100644
index 0000000..43d6957
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java
@@ -0,0 +1,81 @@
+/*
+ * 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.core.config;
+
+import org.apache.tamaya.*;
+import org.apache.tamaya.core.properties.PropertySourceBuilder;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Configuration implementation that stores all current values current a given (possibly dynamic, contextual and non remote
+ * capable instance) and is fully serializable.
+ */
+final class FreezedConfiguration extends AbstractConfiguration implements Serializable{
+ private static final long serialVersionUID = -6373137316556444171L;
+
+ private PropertySource properties;
+
+ /**
+ * Constructor.
+ * @param config The base configuration.
+ */
+ private FreezedConfiguration(Configuration config){
+ super(config.getName());
+ this.properties = PropertySourceBuilder.of(config).buildFrozen();
+ }
+
+ public static final Configuration of(Configuration config){
+ if(config instanceof FreezedConfiguration){
+ return config;
+ }
+ return new FreezedConfiguration(config);
+ }
+
+ @Override
+ public Map<String,String> getProperties(){
+ return properties.getProperties();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FreezedConfiguration that = (FreezedConfiguration) o;
+
+ if (!properties.equals(that.properties)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = properties.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FreezedConfiguration{" +
+ "properties=" + properties +
+ ", name=" + name +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/config/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/MappedConfiguration.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/MappedConfiguration.java
new file mode 100644
index 0000000..736b33e
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/MappedConfiguration.java
@@ -0,0 +1,56 @@
+package org.apache.tamaya.core.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.UnaryOperator;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Configuration implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate areas.
+ */
+class MappedConfiguration extends AbstractConfiguration implements Configuration {
+
+ private static final long serialVersionUID = 8690637705511432083L;
+
+ /** The mapping operator. */
+ private UnaryOperator<String> keyMapper;
+ /** The base configuration. */
+ private Configuration config;
+
+ /**
+ * Creates a new instance.
+ * @param config the base configuration, not null
+ * @param keyMapper The mapping operator, not null
+ */
+ public MappedConfiguration(Configuration config, UnaryOperator<String> keyMapper) {
+ super(config.getName());
+ this.config = Objects.requireNonNull(config);
+ this.keyMapper = Objects.requireNonNull(keyMapper);
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ Map<String, String> result = new HashMap<>();
+ Map<String, String> map = this.config.getProperties();
+ map.forEach((k,v) -> {
+ String targetKey = keyMapper.apply(k);
+ if(targetKey!=null){
+ result.put(targetKey, v);
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.config.isEmpty();
+ }
+
+ @Override
+ public Configuration toConfiguration() {
+ return this;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/MetaConfig.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/MetaConfig.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/MetaConfig.java
new file mode 100644
index 0000000..8d3ad15
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/MetaConfig.java
@@ -0,0 +1,68 @@
+/*
+ * 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.core.internal;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.spi.ServiceContext;
+import org.apache.tamaya.core.properties.ConfigurationFormat;
+import org.apache.tamaya.core.resource.ResourceLoader;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Singleton to read the configuration for the configuration system
+ * fromMap {@code META-INF/config.properties}.
+ * Created by Anatole on 17.10.2014.
+ */
+public final class MetaConfig {
+
+ private static final Logger LOG = Logger.getLogger(MetaConfig.class.getName());
+
+ private static final MetaConfig INSTANCE = new MetaConfig();
+
+ private Map<String,String> properties = new HashMap<>();
+
+ private MetaConfig(){
+ List<Resource> resources = ServiceContext.getInstance().getSingleton(ResourceLoader.class).getResources(MetaConfig.class.getClassLoader(),
+ "classpath:META-INF/config.properties");
+ for(Resource res:resources){
+ try{
+ ConfigurationFormat format = ConfigurationFormat.from(res);
+ Map<String,String> read = format.readConfiguration(res);
+ properties.putAll(read);
+ }
+ catch(Exception e){
+ LOG.log(Level.SEVERE, e, () -> "Error reading meta configuration fromMap " + res);
+ }
+ }
+ }
+
+ public static String getKey(String key){
+ return INSTANCE.properties.get(key);
+ }
+
+ public static String getOrDefault(String key, String defaultValue){
+ return INSTANCE.properties.getOrDefault(key, defaultValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/Utils.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/Utils.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/Utils.java
new file mode 100644
index 0000000..fd490ce
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/Utils.java
@@ -0,0 +1,126 @@
+/*
+ * 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.core.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Utility class simplifying some implementation aspects.
+ * Created by Anatole on 11.11.2014.
+ */
+@SuppressWarnings("unchecked")
+public final class Utils {
+
+ private static final Logger LOG = Logger.getLogger(Utils.class.getName());
+
+ private Utils(){}
+
+ /**
+ * Utility method to read out repeatable annotations.
+ * @param annotated the annotated instance.
+ * @param repeatableAnnotation the repeatable annotation type
+ * @param annotationContainer the container annotation type
+ * @param <T> the repeatable annotation type
+ * @param <R> the repeatable container annotation type
+ * @return a list with the annotations found (could be empty, but never null).
+ */
+ public static <T extends Annotation, R extends Annotation> Collection<T>
+ getAnnotations(AnnotatedElement annotated,
+ Class<T> repeatableAnnotation,
+ Class<R> annotationContainer){
+ List<T> result = new ArrayList<>();
+ R containerAnnot = annotated.getAnnotation(annotationContainer);
+ if(containerAnnot!=null){
+ Method valueMethod;
+ try {
+ valueMethod = annotationContainer.getMethod("keys");
+ result.addAll(Arrays.asList((T[])valueMethod.invoke(containerAnnot)));
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, "Failed to evaluate repeatable annotation.", e);
+ }
+ }
+ else{
+ T annot = annotated.getAnnotation(repeatableAnnotation);
+ if(annot!=null){
+ result.add(annot);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Utility method to read out repeatable annotations.
+ * @param annotated the annotated instance.
+ * @param repeatableAnnotation the repeatable annotation type
+ * @param annotationContainer the container annotation type
+ * @param <T> the repeatable annotation type
+ * @param <R> the repeatable container annotation type
+ * @return a list with the annotations found (could be empty, but never null).
+ */
+ public static <T extends Annotation, R extends Annotation> Collection<T>
+ getAnnotations(AccessibleObject annotated,
+ Class<T> repeatableAnnotation,
+ Class<R> annotationContainer){
+ List<T> result = new ArrayList<>();
+ R containerAnnot = annotated.getAnnotation(annotationContainer);
+ if(containerAnnot!=null){
+ Method valueMethod;
+ try {
+ valueMethod = annotationContainer.getMethod("keys");
+ result.addAll(Arrays.asList((T[])valueMethod.invoke(containerAnnot)));
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, "Failed to evaluate repeatable annotation.", e);
+ }
+ }
+ else{
+ T annot = annotated.getAnnotation(repeatableAnnotation);
+ if(annot!=null){
+ result.add(annot);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Utility method to read out repeatable annotations.
+ * @param annotationType the annotation type.
+ * @param objects the accessible objects to be looked up
+ * @param <T> the repeatable annotation type
+ * @return a list with the annotations found (could be empty, but never null).
+ */
+ public static <T extends Annotation> T getAnnotation(
+ Class<T> annotationType, AnnotatedElement... objects){
+ for(AnnotatedElement obj:objects){
+ T annot = obj.getAnnotation(annotationType);
+ if(annot!=null){
+ return annot;
+ }
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationSpi.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationSpi.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationSpi.java
new file mode 100644
index 0000000..8b7180c
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultConfigurationSpi.java
@@ -0,0 +1,116 @@
+/*
+ * 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.core.internal.config;
+
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.internal.el.DefaultExpressionEvaluator;
+import org.apache.tamaya.core.internal.inject.ConfigTemplateInvocationHandler;
+import org.apache.tamaya.core.internal.inject.ConfigurationInjector;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+import org.apache.tamaya.core.spi.ExpressionEvaluator;
+import org.apache.tamaya.spi.ConfigurationSpi;
+import org.apache.tamaya.spi.ServiceContext;
+
+
+/**
+ * Default SPI that implements the behaviour of {@link org.apache.tamaya.spi.ConfigurationSpi}.
+ */
+@SuppressWarnings("unchecked")
+public class DefaultConfigurationSpi implements ConfigurationSpi {
+
+ private static final String DEFAULT_CONFIG_NAME = "default";
+
+ private Map<String, ConfigurationProviderSpi> configProviders = new ConcurrentHashMap<>();
+
+ private ExpressionEvaluator expressionEvaluator = loadEvaluator();
+
+ private ExpressionEvaluator loadEvaluator() {
+ ExpressionEvaluator eval = ServiceContext.getInstance().getService(ExpressionEvaluator.class).orElse(null);
+ if (eval == null) {
+ eval = new DefaultExpressionEvaluator();
+ }
+ return eval;
+ }
+
+ public DefaultConfigurationSpi() {
+ if(configProviders.isEmpty()) {
+ for (ConfigurationProviderSpi spi : ServiceContext.getInstance().getServices(ConfigurationProviderSpi.class, Collections.emptyList())) {
+ configProviders.put(spi.getConfigName(), spi);
+ }
+ }
+ }
+
+ @Override
+ public <T> T createTemplate(Class<T> type, Configuration... configurations) {
+ ClassLoader cl = Optional.ofNullable(Thread.currentThread()
+ .getContextClassLoader()).orElse(getClass().getClassLoader());
+ return (T) Proxy.newProxyInstance(cl, new Class[]{type}, new ConfigTemplateInvocationHandler(type, configurations));
+ }
+
+ /**
+ *
+ * @param instance the instance with configuration annotations, not null.
+ * @param configurations the configurations to be used for evaluating the values for injection into {@code instance}.
+ * If no items are passed, the default configuration is used.
+ */
+ @Override
+ public void configure(Object instance, Configuration... configurations) {
+ ConfigurationInjector.configure(instance, configurations);
+ }
+
+
+ @Override
+ public String evaluateValue(String expression, Configuration... configurations) {
+ return expressionEvaluator.evaluate(expression, configurations);
+ }
+
+ @Override
+ public boolean isConfigurationAvailable(String name) {
+ ConfigurationProviderSpi spi = this.configProviders.get(name);
+ return spi != null;
+ }
+
+ @Override
+ public Configuration getConfiguration(String name) {
+ ConfigurationProviderSpi provider = configProviders.get(name);
+ if (provider == null) {
+ if (DEFAULT_CONFIG_NAME.equals(name)) {
+ provider = new FallbackSimpleConfigProvider();
+ configProviders.put(DEFAULT_CONFIG_NAME, provider);
+ } else {
+ throw new ConfigException("No such config: " + name);
+ }
+ }
+ Configuration config = provider.getConfiguration();
+ if (config == null) {
+ throw new ConfigException("No such config: " + name);
+ }
+ return config;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java
new file mode 100644
index 0000000..f1b14e0
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java
@@ -0,0 +1,168 @@
+/*
+ * 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.core.internal.config;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.Currency;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.PropertyAdapter;
+import org.apache.tamaya.annotation.WithPropertyAdapter;
+import org.apache.tamaya.spi.PropertyAdapterSpi;
+
+/**
+ * Default codecs singleton, which provides default codesc for all kind of classes out of the box, which will be
+ * instantiatable from configuration, if one of the following is given:
+ * <ul>
+ * <li>static factory methods using a String as simgle argument, called {@code of, valueOf, getInstance, instance, parse}</li>
+ * <li>have constructors taking a single String</li>
+ * </ul>
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class DefaultPropertyAdapterSpi implements PropertyAdapterSpi {
+
+
+ private Map<Class,PropertyAdapter> adapters = new ConcurrentHashMap<>();
+
+ public DefaultPropertyAdapterSpi(){
+ // Add default adapters
+ register(char.class, (s) -> s.charAt(0));
+ register(byte.class, Byte::parseByte);
+ register(short.class, Short::parseShort);
+ register(int.class, Integer::parseInt);
+ register(long.class, Long::parseLong);
+ register(boolean.class, Boolean::parseBoolean);
+ register(float.class, Float::parseFloat);
+ register(double.class, Double::parseDouble);
+
+ register(Character.class, (s) -> s.charAt(0));
+ register(Byte.class, Byte::valueOf);
+ register(Short.class, Short::valueOf);
+ register(Integer.class, Integer::valueOf);
+ register(Long.class, Long::valueOf);
+ register(Boolean.class, Boolean::valueOf);
+ register(Float.class, Float::valueOf);
+ register(Double.class, Double::valueOf);
+ register(BigDecimal.class, BigDecimal::new);
+ register(BigInteger.class, BigInteger::new);
+
+ register(Currency.class, Currency::getInstance);
+
+ register(LocalDate.class, LocalDate::parse);
+ register(LocalTime.class, LocalTime::parse);
+ register(LocalDateTime.class, LocalDateTime::parse);
+ register(ZoneId.class, ZoneId::of);
+ }
+
+ @Override
+ public <T> PropertyAdapter<T> register(Class<T> targetType, PropertyAdapter<T> adapter){
+ return adapters.put(targetType, adapter);
+ }
+
+ @Override
+ public <T> PropertyAdapter<T> getPropertyAdapter(Class<T> targetType, WithPropertyAdapter adapterAnnot){
+ PropertyAdapter codec = null;
+ Class<? extends PropertyAdapter> configuredCodec = null;
+ if(adapterAnnot != null){
+ configuredCodec = adapterAnnot.value();
+ if(!configuredCodec.equals(PropertyAdapter.class)){
+ try{
+ codec = configuredCodec.newInstance();
+ }
+ catch(Exception e){
+ throw new ConfigException("Invalid codec configured.", e);
+ }
+ }
+ }
+ if(codec == null){
+ codec = adapters.get(targetType);
+ }
+ if(codec == null){
+ codec = getDefaultPropertyAdapter(targetType);
+ }
+ if(codec == null){
+ throw new ConfigException("No Codec found for " + targetType.getName());
+ }
+ return codec;
+ }
+
+ private <T> PropertyAdapter getDefaultPropertyAdapter(Class<T> targetType) {
+ PropertyAdapter<T> decoder = null;
+ Method factoryMethod = getFactoryMethod(targetType, "of", "valueOf", "instanceOf", "getInstance", "from", "parse");
+ if(factoryMethod!=null){
+ decoder = (s) -> {
+ try{
+ factoryMethod.setAccessible(true);
+ return targetType.cast(factoryMethod.invoke(s));
+ }
+ catch (Exception e){
+ throw new ConfigException("Failed to decode '"+s+"'", e);
+ }
+ };
+ }
+ if(decoder==null) {
+ try {
+ Constructor<T> constr = targetType.getDeclaredConstructor(String.class);
+ decoder = (s) -> {
+ try{
+ constr.setAccessible(true);
+ return constr.newInstance(s);
+ }
+ catch (Exception e){
+ throw new ConfigException("Failed to decode '"+s+"'", e);
+ }
+ };
+ } catch (Exception e) {
+ // ignore, TODO log finest
+ }
+ }
+ if(decoder!=null) {
+ return register(targetType, decoder);
+ }
+ return null;
+ }
+
+ private Method getFactoryMethod(Class<?> type, String... methodNames) {
+ Method m;
+ for(String name:methodNames){
+ try{
+ m = type.getDeclaredMethod(name, String.class);
+ return m;
+ }
+ catch(Exception e){
+ // ignore, TODO log finest
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isTargetTypeSupported(Class<?> targetType){
+ return adapters.containsKey(targetType);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
new file mode 100644
index 0000000..6fd4672
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/EnvPropertiesConfigProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.core.internal.config;
+
+import org.apache.tamaya.core.properties.PropertySourceBuilder;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Provides a {@link org.apache.tamaya.Configuration} named 'environment.properties'
+ * containing the current environment properties.
+ *
+ * Created by Anatole on 29.09.2014.
+ */
+public class EnvPropertiesConfigProvider implements ConfigurationProviderSpi{
+
+ private Configuration envConfig;
+
+ public EnvPropertiesConfigProvider(){
+ envConfig = Configuration.from(PropertySourceBuilder.of("environment.properties").addEnvironmentProperties().build());
+ }
+
+ @Override
+ public String getConfigName(){
+ return "environment.properties";
+ }
+
+ @Override
+ public Configuration getConfiguration(){
+ return envConfig;
+ }
+
+ @Override
+ public void reload() {
+ // nothing todo here
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java
new file mode 100644
index 0000000..7bcfb77
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java
@@ -0,0 +1,60 @@
+package org.apache.tamaya.core.internal.config;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.properties.AggregationPolicy;
+import org.apache.tamaya.core.properties.PropertySourceBuilder;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+/**
+ * Implementation of a default config provider used as fallback, if no {@link org.apache.tamaya.core.spi.ConfigurationProviderSpi}
+ * instance is registered for providing the {@code default} {@link org.apache.tamaya.Configuration}. The providers loads the follwing
+ * config resources:
+ * <ul>
+ * <li>Classpath: META-INF/cfg/default/**/*.xml, META-INF/cfg/default/**/*.properties, META-INF/cfg/default/**/*.ini</li>
+ * <li>Classpath: META-INF/cfg/config/#42;#42;/#42;.xml, META-INF/cfg/config/#42;#42;/#42;.properties, META-INF/cfg/config/#42;#42;/#42;.ini</li>
+ * <li>Files: defined by the system property -Dconfig.dir</li>
+ * <li>system properties</li>
+ * </ul>
+ */
+public class FallbackSimpleConfigProvider implements ConfigurationProviderSpi {
+
+ private static final String DEFAULT_CONFIG_NAME = "default";
+
+ /**
+ * The loaded configuration instance.
+ */
+ private volatile Configuration configuration;
+
+ @Override
+ public String getConfigName() {
+ return DEFAULT_CONFIG_NAME;
+ }
+
+ @Override
+ public Configuration getConfiguration() {
+ Configuration cfg = configuration;
+ if (cfg == null) {
+ reload();
+ cfg = configuration;
+ }
+ return cfg;
+ }
+
+
+ @Override
+ public void reload() {
+ this.configuration = Configuration.from(
+ PropertySourceBuilder.of(DEFAULT_CONFIG_NAME)
+ .addProviders(PropertySourceBuilder.of("CL default")
+ .withAggregationPolicy(AggregationPolicy.LOG_ERROR)
+ .addPaths("META-INF/cfg/default/**/*.xml", "META-INF/cfg/default/**/*.properties", "META-INF/cfg/default/**/*.ini")
+ .build())
+ .addProviders(PropertySourceBuilder.of("CL default")
+ .withAggregationPolicy(AggregationPolicy.LOG_ERROR)
+ .addPaths("META-INF/cfg/config/**/*.xml", "META-INF/cfg/config/**/*.properties", "META-INF/cfg/config/**/*.ini")
+ .build())
+ .addSystemProperties()
+ .addEnvironmentProperties()
+ .build());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeListener.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeListener.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeListener.java
new file mode 100644
index 0000000..afd1199
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeListener.java
@@ -0,0 +1,137 @@
+package org.apache.tamaya.core.internal.config;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.log4j.Logger;
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+/**
+ * Class that has the responsibility to watch the folder and then commit the {@link ConfigurationProviderSpi}
+ * to commit the Configuration from the properties or xml files, another ones will be ignored.
+ * @see FilesPropertiesConfigProvider
+ * This listener will wait to events and wait to one second to watch again.
+ * <p>If new file was created or modified will commit from this file.</p>
+ * <p>If a file was removed then the listener will load using all files left.</p>
+ * @author otaviojava
+ */
+class FileChangeListener implements Runnable {
+
+ private static final Logger LOGGER = Logger.getLogger(FileChangeListener.class);
+
+ private WatchService watchService;
+
+ private FileChangeObserver observer;
+
+ private Map<String, String> configurationMap;
+
+ private Path directory;
+
+ private FileReader fileReader = new FileReader();
+
+ public FileChangeListener(FileChangeObserver observer, Map<String, String> mapConfiguration, Path directory) {
+ this.observer = observer;
+ this.configurationMap = mapConfiguration;
+ this.directory = directory;
+ this.watchService = getWatchService();
+
+ if (Objects.nonNull(watchService) && Objects.nonNull(directory)) {
+ try {
+ directory.register(watchService, ENTRY_DELETE, ENTRY_MODIFY,
+ ENTRY_CREATE);
+ } catch (IOException e) {
+ throw new FileChangeListenerException("An error happened when does try to registry to watch the folder", e);
+ }
+ }
+ }
+
+
+ @Override
+ public void run() {
+ if (Objects.isNull(watchService) || Objects.isNull(directory)) {
+ return;
+ }
+ while (true) {
+ watchFolder();
+ }
+ }
+
+
+ private void watchFolder() {
+ try {
+ WatchKey watckKey = watchService.take();
+ boolean needUpdate = false;
+ for (WatchEvent<?> event : watckKey.pollEvents()) {
+ Path keyDirectory = (Path) watckKey.watchable();
+ if(listenerPath(event, keyDirectory)) {
+ needUpdate = true;
+ }
+ }
+
+ if (needUpdate) {
+ observer.update(configurationMap);
+ }
+ watckKey.reset();
+ Thread.sleep(1_000L);
+ } catch (Exception e) {
+ throw new FileChangeListenerException("An error happened when does try to watch the folder", e);
+ }
+ }
+
+ private boolean listenerPath(WatchEvent<?> event, Path keyDirectory) {
+ boolean wasModified = false;
+ Path path = keyDirectory.resolve((Path)event.context());
+ if(fileReader.isObservavleFile(path)) {
+
+ if (event.kind() == ENTRY_CREATE || event.kind() == ENTRY_MODIFY) {
+ wasModified = true;
+ configurationMap.putAll(fileReader.runFile(path.toAbsolutePath()));
+ LOGGER.info("An event was detected in file: " + path.getFileName());
+ }
+
+ if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
+ wasModified = true;
+ configurationMap = fileReader.runFiles(directory);
+ LOGGER.info("A remotion event was detected in file: " + path.getFileName());
+ }
+
+ } else {
+ LOGGER.info("Ignoring the file: " + path.getFileName() + " because is not a properties or xml file");
+ }
+ return wasModified;
+ }
+
+ private WatchService getWatchService() {
+ try {
+ FileSystem fileSystem = Paths.get(".").getFileSystem();
+ return fileSystem.newWatchService();
+ } catch (IOException e) {
+ LOGGER.warn("This file System does not supports WatchService", e);
+ return null;
+ }
+
+ }
+
+ class FileChangeListenerException extends ConfigException {
+
+ private static final long serialVersionUID = -8965486770881001513L;
+
+ public FileChangeListenerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeObserver.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeObserver.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeObserver.java
new file mode 100644
index 0000000..a7d4ba9
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileChangeObserver.java
@@ -0,0 +1,13 @@
+package org.apache.tamaya.core.internal.config;
+
+import java.util.Map;
+
+/**
+ * Observer to be used in {@link FileChangeListener} to commit all configurations and provider.
+ * @author otaviojava
+ */
+interface FileChangeObserver {
+
+ void update(Map<String, String> configurationMap);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java
new file mode 100644
index 0000000..4f76180
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java
@@ -0,0 +1,68 @@
+package org.apache.tamaya.core.internal.config;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Implementation of Configuration which the information is from xml or properties files.
+ * Once the File modified, it will commit automatically by provider.
+ * @see FilesPropertiesConfigProvider
+ * @see FileChangeObserver
+ * @author otaviojava
+ */
+class FileConfiguration implements Configuration, FileChangeObserver {
+
+ private Map<String, String> configurationMap;
+
+ public FileConfiguration(Map<String, String> configurationMap) {
+ this.configurationMap = configurationMap;
+ }
+
+ @Override
+ public Optional<String> get(String key) {
+ return Optional.ofNullable(configurationMap.get(key));
+ }
+
+ @Override
+ public String getName() {
+ return "files.config";
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return configurationMap;
+ }
+
+ @Override
+ public void update(Map<String, String> configurationMap) {
+ synchronized (this) {
+ this.configurationMap = configurationMap;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "org.apache.tamaya.core.internal.config.FileConfiguration: " + configurationMap.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(configurationMap);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(Configuration.class.isInstance(obj)) {
+ Configuration other = Configuration.class.cast(obj);
+ return Objects.equals(configurationMap, other.getProperties());
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileReader.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileReader.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileReader.java
new file mode 100644
index 0000000..287ccc4
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FileReader.java
@@ -0,0 +1,80 @@
+package org.apache.tamaya.core.internal.config;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Class to read a file and creates a {@link Map} of {@link String}.
+ * The implementation of {@link Map} will {@link HashMap}
+ * @author otaviojava
+ */
+class FileReader {
+
+ private static final String EXTENSIONS_ACCEPTED = "*.{xml,properties}";
+
+ public Map<String, String> runFiles(Path directory) {
+ Properties properties = createProperties(directory);
+ return properties
+ .stringPropertyNames()
+ .stream()
+ .collect(
+ Collectors.toMap(Function.identity(),
+ properties::getProperty));
+ }
+
+ public Map<String, String> runFile(Path path) {
+ Properties properties = new Properties();
+ try {
+ loadFile(properties, path);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return properties
+ .stringPropertyNames()
+ .stream()
+ .collect(
+ Collectors.toMap(Function.identity(),
+ properties::getProperty));
+ }
+
+ private Properties createProperties(Path directory) {
+ Properties properties = new Properties();
+
+ try {
+ for (Path path : Files.newDirectoryStream(directory, EXTENSIONS_ACCEPTED)) {
+ loadFile(properties, path);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return properties;
+ }
+
+ private void loadFile(Properties properties, Path path) throws IOException,
+ InvalidPropertiesFormatException {
+ if (isXmlExtension(path)) {
+ properties.loadFromXML(Files.newInputStream(path));
+ } else {
+ properties.load(Files.newInputStream(path));
+ }
+}
+
+ private boolean isXmlExtension(Path path) {
+ return path.toString().toLowerCase().endsWith(".xml");
+ }
+
+ private boolean isPropertiesExtension(Path path) {
+ return path.toString().toLowerCase().endsWith(".properties");
+ }
+
+ public boolean isObservavleFile(Path path) {
+ return isPropertiesExtension(path) || isXmlExtension(path);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FilesPropertiesConfigProvider.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FilesPropertiesConfigProvider.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FilesPropertiesConfigProvider.java
new file mode 100644
index 0000000..c2cf7fa
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/FilesPropertiesConfigProvider.java
@@ -0,0 +1,97 @@
+package org.apache.tamaya.core.internal.config;
+
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+/**
+ * This implementation run in a folder and once found xml and properties files
+ * will create the Configuration, when one file is created, deleted or modified the configuration will commit
+ * automatically.
+ * The default folder is META-INF/configuration, but you can change using the absolute path in
+ * "-Dtamaya.configbase" parameter.
+ * @author otaviojava
+ */
+public class FilesPropertiesConfigProvider implements ConfigurationProviderSpi, FileChangeObserver {
+
+ private static final String DEFAULT_CONFIG_NAME = "files.configuration";
+
+ private Map<String, String> configurationMap = Collections.emptyMap();
+
+ private ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ private List<FileChangeObserver> fileChangeObservers = new ArrayList<>();
+
+ public FilesPropertiesConfigProvider() {
+ Path directory = getDirectory();
+ if (Objects.nonNull(directory)) {
+ configurationMap = new FileReader().runFiles(directory);
+ Runnable runnable = new FileChangeListener(this, configurationMap, directory);
+ executor.execute(runnable);
+ } else {
+ executor.shutdown();
+ }
+ }
+
+ @Override
+ public String getConfigName() {
+ return DEFAULT_CONFIG_NAME;
+ }
+
+ private Path getDirectory() {
+ String absolutePath = System.getProperty("tamaya.configbase");
+
+ if(Objects.nonNull(absolutePath)) {
+ Path path = Paths.get(absolutePath);
+ if(Files.isDirectory(path)) {
+ return path;
+ }
+ }
+
+ URL resource = FilesPropertiesConfigProvider.class.getResource("/META-INF/configuration/");
+ if (Objects.nonNull(resource)) {
+ try {
+ return Paths.get(resource.toURI());
+ } catch (URISyntaxException e) {
+ throw new ConfigException("An error to find the directory to watch", e);
+ }
+ }
+ return null;
+ }
+
+
+ @Override
+ public Configuration getConfiguration() {
+ return new FileConfiguration(Collections.unmodifiableMap(configurationMap));
+ }
+
+ @Override
+ public void reload() {
+ Path directory = getDirectory();
+ if (Objects.nonNull(directory)) {
+ configurationMap = new FileReader().runFiles(directory);
+ }
+ }
+
+ @Override
+ public void update(Map<String, String> configurationMap) {
+ synchronized (this) {
+ this.configurationMap = configurationMap;
+ Map<String, String> unmodifiableMap = Collections.unmodifiableMap(configurationMap);
+ fileChangeObservers.forEach(fi -> fi.update(unmodifiableMap));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
new file mode 100644
index 0000000..cdd90b2
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/config/SystemPropertiesConfigProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.core.internal.config;
+
+import org.apache.tamaya.core.properties.PropertySourceBuilder;
+import org.apache.tamaya.core.spi.ConfigurationProviderSpi;
+
+import org.apache.tamaya.Configuration;
+
+/**
+ * Provides a {@link org.apache.tamaya.Configuration} named 'system.properties'
+ * containing the current system properties.
+ *
+ * Created by Anatole on 29.09.2014.
+ */
+public class SystemPropertiesConfigProvider implements ConfigurationProviderSpi{
+
+ private Configuration systemConfig;
+
+ public SystemPropertiesConfigProvider(){
+ systemConfig = Configuration.from(PropertySourceBuilder.of("system.properties").addSystemProperties().build());
+ }
+
+ @Override
+ public String getConfigName(){
+ return "system.properties";
+ }
+
+ @Override
+ public Configuration getConfiguration(){
+ return systemConfig;
+ }
+
+ @Override
+ public void reload() {
+ // nothing todo here
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java
new file mode 100644
index 0000000..457aa6c
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/DefaultExpressionEvaluator.java
@@ -0,0 +1,144 @@
+/*
+ * 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.core.internal.el;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.spi.ServiceContext;
+import org.apache.tamaya.core.spi.ExpressionEvaluator;
+import org.apache.tamaya.core.spi.ExpressionResolver;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Default expression evaluator that manages several instances of {@link org.apache.tamaya.core.spi.ExpressionResolver}.
+ * Each resolver is identified by a resolver id. Each expression passed has the form resolverId:resolverExpression, which
+ * has the advantage that different resolvers can be active in parallel.
+ */
+public final class DefaultExpressionEvaluator implements ExpressionEvaluator{
+
+ private Map<String, ExpressionResolver> resolvers = new ConcurrentHashMap<>();
+
+ private ExpressionResolver defaultResolver;
+
+ public DefaultExpressionEvaluator() {
+ for(ExpressionResolver resolver: ServiceContext.getInstance().getServices(ExpressionResolver.class)){
+ resolvers.put(resolver.getResolverId(), resolver);
+ }
+ defaultResolver = ServiceContext.getInstance().getSingleton(ExpressionResolver.class);
+ }
+
+ /**
+ * Resolves an expression in the form current <code>${resolverId:expression}</code>. The expression can be
+ * part current any type current literal text. Also multiple expression, with different resolver ids are supported.
+ * All control characters (${}\) can be escaped.<br>
+ * So all the following are valid expressions:
+ * <ul>
+ * <li><code>${resolverId:expression}</code></li>
+ * <li><code>bla bla ${resolverId:expression}</code></li>
+ * <li><code>${resolverId:expression} bla bla</code></li>
+ * <li><code>bla bla ${resolverId:expression} bla bla</code></li>
+ * <li><code>${resolverId:expression}${resolverId2:expression2}</code></li>
+ * <li><code>foo ${resolverId:expression}${resolverId2:expression2}</code></li>
+ * <li><code>foo ${resolverId:expression} bar ${resolverId2:expression2}</code></li>
+ * <li><code>${resolverId:expression}foo${resolverId2:expression2}bar</code></li>
+ * <li><code>foor${resolverId:expression}bar${resolverId2:expression2}more</code></li>
+ * <li><code>\${resolverId:expression}foo${resolverId2:expression2}bar</code> (first expression is escaped).</li>
+ * </ul>
+ *
+ * @param expression the expression to be evaluated, not null
+ * @param configurations overriding configurations to be used for evaluating the values for injection into {@code instance}.
+ * If no such config is passed, the default configurations provided by the current
+ * registered providers are used.
+ * @return the evaluated expression.
+ * @throws org.apache.tamaya.ConfigException if resolution fails.
+ */
+ @Override
+ public String evaluate(String expression, Configuration... configurations) {
+ StringTokenizer tokenizer = new StringTokenizer(expression, "${}\\", true);
+ boolean escaped = false;
+ StringBuilder resolvedValue = new StringBuilder();
+ StringBuilder current = new StringBuilder();
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (escaped) {
+ switch (token) {
+ case "n":
+ current.append("\n");
+ break;
+ case "r":
+ current.append("\r");
+ break;
+ case "t":
+ current.append("\t");
+ break;
+ default:
+ current.append(token);
+ break;
+ }
+ escaped = false;
+ continue;
+ }
+ switch (token) {
+ case "\\":
+ escaped = true;
+ break;
+ case "$":
+ if (current.length() > 0) {
+ resolvedValue.append(current);
+ current.setLength(0);
+ }
+ if (!"{".equals(tokenizer.nextToken())) {
+ throw new ConfigException("Invalid expression encountered: " + expression);
+ }
+ String subExpression = tokenizer.nextToken();
+ if (!"}".equals(tokenizer.nextToken())) {
+ throw new ConfigException("Invalid expression encountered: " + expression);
+ }
+ // evaluate sub-expression
+ current.append(evaluteInternal(subExpression));
+ break;
+ default:
+ current.append(token);
+ }
+ }
+ if (current.length() > 0) {
+ resolvedValue.append(current);
+ }
+ return resolvedValue.toString();
+ }
+
+ private String evaluteInternal(String subExpression) {
+ int sepPos = subExpression.indexOf(':');
+ if (sepPos > 0) {
+ String refID = subExpression.substring(0, sepPos);
+ String expression = subExpression.substring(sepPos + 1);
+ return Optional.ofNullable(this.resolvers.get(refID)).orElseThrow(
+ () -> new ConfigException("Resolver not found: " + refID + " in " + subExpression)
+ ).resolve(expression);
+ } else {
+ return Optional.ofNullable(this.defaultResolver).orElseThrow(
+ () -> new ConfigException("No default Resolver set, but required by " + subExpression)
+ ).resolve(subExpression);
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/EnvironmentPropertyResolver.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/EnvironmentPropertyResolver.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/EnvironmentPropertyResolver.java
new file mode 100644
index 0000000..68d37a4
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/EnvironmentPropertyResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.core.internal.el;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.spi.ExpressionResolver;
+
+import java.util.Optional;
+
+/**
+ * Property resolver implementation that interprets the resolver expressions as environment properties.
+ */
+public final class EnvironmentPropertyResolver implements ExpressionResolver{
+
+ @Override
+ public String getResolverId() {
+ return "env";
+ }
+
+ @Override
+ public String resolve(String expression, Configuration... configurations){
+ return Optional.ofNullable(System.getenv(expression)).orElseThrow(
+ () -> new ConfigException("No such environment property: " + expression)
+ );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/SystemPropertyResolver.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/SystemPropertyResolver.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/SystemPropertyResolver.java
new file mode 100644
index 0000000..c6eb298
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/el/SystemPropertyResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.core.internal.el;
+
+import java.util.Optional;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.spi.ExpressionResolver;
+
+/**
+ * Property resolver implementation that interprets the resolver expression as system property name.
+ */
+public final class SystemPropertyResolver implements ExpressionResolver{
+
+ @Override
+ public String getResolverId() {
+ return "sys";
+ }
+
+ @Override
+ public String resolve(String expression, Configuration... configurations){
+ return Optional.ofNullable(System.getProperty(expression)).orElseThrow(
+ () -> new ConfigException("No such system property: " + expression)
+ );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigurationFormatSpi.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigurationFormatSpi.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigurationFormatSpi.java
new file mode 100644
index 0000000..eac0a3b
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/DefaultConfigurationFormatSpi.java
@@ -0,0 +1,78 @@
+/*
+ * 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.core.internal.format;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.core.properties.ConfigurationFormat;
+import org.apache.tamaya.core.spi.ConfigurationFormatSpi;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import org.apache.tamaya.spi.ServiceContext;
+
+/**
+ * Singleton accessor to access registered reader mechanism.
+ */
+public final class DefaultConfigurationFormatSpi implements ConfigurationFormatSpi {
+
+ public ConfigurationFormat getFormat(String formatName){
+ Objects.requireNonNull(formatName);
+ try {
+ for (ConfigurationFormat configFormat : ServiceContext.getInstance().getServices(ConfigurationFormat.class)) {
+ if(formatName.equals(configFormat.getFormatName())){
+ return configFormat;
+ }
+ }
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public Collection<String> getFormatNames(){
+ Set<String> result = new HashSet<>();
+ try {
+ result.addAll(ServiceContext.getInstance().getServices(ConfigurationFormat.class).stream().map(ConfigurationFormat::getFormatName)
+ .collect(Collectors.toList()));
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ public ConfigurationFormat getFormat(Resource resource) {
+ Objects.requireNonNull(resource);
+ try {
+ for (ConfigurationFormat configFormat : ServiceContext.getInstance().getServices(ConfigurationFormat.class)) {
+ if(configFormat.isAccepted(resource)){
+ return configFormat;
+ }
+ }
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
new file mode 100644
index 0000000..85ce778
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/IniFormat.java
@@ -0,0 +1,98 @@
+/*
+ * 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.core.internal.format;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.core.properties.ConfigurationFormat;
+
+
+import org.apache.tamaya.ConfigException;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class IniFormat implements ConfigurationFormat{
+
+ private static final Logger LOG = Logger.getLogger(IniFormat.class.getName());
+
+
+ @Override
+ public String getFormatName(){
+ return "ini";
+ }
+
+ @Override
+ public boolean isAccepted(Resource resource){
+ String path = resource.getFilename();
+ return path != null && path.endsWith(".ini");
+ }
+
+ @Override
+ public Map<String,String> readConfiguration(Resource resource){
+ Map<String,String> result = new HashMap<>();
+ if(isAccepted(resource) && resource.exists()){
+ try(InputStream is = resource.getInputStream()){
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String line = reader.readLine();
+ int lineNum = 0;
+ String section = null;
+ while(line != null){
+ lineNum++;
+ line = line.trim();
+ if(line.isEmpty()){
+ line = reader.readLine();
+ continue;
+ }
+ if(line.trim().startsWith("#")){
+ // comment
+ }
+ else if(line.startsWith("[")){
+ int end = line.indexOf(']');
+ if(end < 0){
+ throw new ConfigException(
+ "Invalid INI-Format, ']' expected, at " + lineNum + " in " + resource);
+ }
+ section = line.substring(1, end);
+ }
+ else{
+ int sep = line.indexOf('=');
+ String key = line.substring(0,sep);
+ String value = line.substring(sep+1);
+ if(section!=null){
+ result.put(section + '.' + key, value);
+ }
+ else{
+ result.put(key, value);
+ }
+ }
+ line = reader.readLine();
+ }
+ }
+ catch(Exception e){
+ LOG.log(Level.SEVERE, e, () -> "Could not read configuration: " + resource);
+ }
+ }
+ return result;
+ }
+
+}