You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by pl...@apache.org on 2015/01/25 13:47:58 UTC
incubator-tamaya git commit: TAMAYA-60 Small changes to the core
implementation of some classes needed for the builder.
Repository: incubator-tamaya
Updated Branches:
refs/heads/master 2cfbed338 -> cd93d8d28
TAMAYA-60 Small changes to the core implementation of some classes needed for the builder.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/cd93d8d2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/cd93d8d2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/cd93d8d2
Branch: refs/heads/master
Commit: cd93d8d2828875af58f657182b6ae8bd6efcff6b
Parents: 2cfbed3
Author: Oliver B. Fischer <pl...@apache.org>
Authored: Sun Jan 25 13:47:09 2015 +0100
Committer: Oliver B. Fischer <pl...@apache.org>
Committed: Sun Jan 25 13:47:09 2015 +0100
----------------------------------------------------------------------
.../tamaya/core/internal/BaseConfiguration.java | 229 +++++++++++++++++++
.../core/internal/BaseConfigurationContext.java | 143 +++++++++++-
.../core/internal/DefaultConfiguration.java | 193 +---------------
.../internal/DefaultConfigurationContext.java | 127 +---------
modules/builder/pom.xml | 7 +
.../tamaya/builder/ConfigurationBuilder.java | 38 ++-
.../builder/ProgrammaticConfiguration.java | 41 ++++
.../ProgrammaticConfigurationContext.java | 32 +++
.../builder/ConfigurationBuilderTest.java | 18 +-
9 files changed, 510 insertions(+), 318 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfiguration.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfiguration.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfiguration.java
new file mode 100644
index 0000000..a8679cc
--- /dev/null
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfiguration.java
@@ -0,0 +1,229 @@
+/*
+ * 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.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertyConverter;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ * Base class for custom {@link org.apache.tamaya.Configuration}
+ * implementations with default implementations for many common
+ * methods.
+ */
+public abstract class BaseConfiguration implements Configuration {
+ /**
+ * The logger.
+ */
+ private static final Logger LOG = Logger.getLogger(BaseConfiguration.class.getName());
+ /**
+ * The maximal number of filter cycles performed before aborting.
+ */
+ private static final int MAX_FILTER_LOOPS = 10;
+
+
+ abstract protected ConfigurationContext getConfigurationContext();
+
+ /**
+ * Apply filters to a single property value.
+ *
+ * @param key the key, used for logging, not null.
+ * @param unfilteredValue the unfiltered property value.
+ * @return the filtered value, or null.
+ */
+ private String applyFilter(String key, String unfilteredValue) {
+ // Apply filters to values, prevent values filtered to null!
+ for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
+ boolean changed = false;
+ // Apply filters to values, prevent values filtered to null!
+ for (PropertyFilter filter : getConfigurationContext().getPropertyFilters()) {
+ String newValue = filter.filterProperty(key, unfilteredValue);
+ if (newValue != null && !newValue.equals(unfilteredValue)) {
+ changed = true;
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+ }
+ } else if (unfilteredValue != null && !unfilteredValue.equals(newValue)) {
+ changed = true;
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
+ }
+ }
+ unfilteredValue = newValue;
+ }
+ if (!changed) {
+ LOG.finest(() -> "Finishing filter loop, no changes detected.");
+ break;
+ } else {
+ if (i == (MAX_FILTER_LOOPS - 1)) {
+ if (LOG.isLoggable(Level.WARNING)) {
+ LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
+ }
+ } else {
+ LOG.finest(() -> "Repeating filter loop, changes detected.");
+ }
+ }
+ }
+ return unfilteredValue;
+ }
+
+
+ /**
+ * This method evaluates the given configuration key. Hereby if goes down the chain or PropertySource instances
+ * provided by the current {@link org.apache.tamaya.spi.ConfigurationContext}. The first non-null-value returned
+ * is taken as an intermediate value. Finally the value is filtered through the
+ * {@link org.apache.tamaya.spi.PropertyFilter} instances installed, before it is returned as the final result of
+ * this method.
+ *
+ * @param key the property's key, not null.
+ * @return the optional configuration value, never null.
+ */
+ @Override
+ public String get(String key) {
+ List<PropertySource> propertySources = getConfigurationContext().getPropertySources();
+ String unfilteredValue = null;
+ for (PropertySource propertySource : propertySources) {
+ String value = propertySource.get(key);
+ if (value != null) {
+ unfilteredValue = value.length() > 0 ? value : null;
+ break;
+ }
+ }
+ return applyFilter(key, unfilteredValue);
+ }
+
+
+
+ /**
+ * Get the current properties, composed by the loaded {@link org.apache.tamaya.spi.PropertySource} and filtered
+ * by registered {@link org.apache.tamaya.spi.PropertyFilter}.
+ *
+ * @return the final properties.
+ */
+ @Override
+ public Map<String, String> getProperties() {
+ List<PropertySource> propertySources = new ArrayList<>(getConfigurationContext().getPropertySources());
+ Collections.reverse(propertySources);
+ Map<String, String> result = new HashMap<>();
+ for (PropertySource propertySource : propertySources) {
+ try {
+ int origSize = result.size();
+ Map<String, String> otherMap = propertySource.getProperties();
+ LOG.log(Level.FINEST, null, () -> "Overriding with properties from " + propertySource.getName());
+ result.putAll(otherMap);
+ LOG.log(Level.FINEST, null, () -> "Handled properties from " + propertySource.getName() + "(new: " +
+ (result.size() - origSize) + ", overrides: " + origSize + ", total: " + result.size());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, "Error adding properties from PropertySource: " + propertySource + ", ignoring PropertySource.", e);
+ }
+ }
+ return applyFilters(result);
+ }
+
+ /**
+ * Filter a full configuration property map.
+ *
+ * @param inputMap the unfiltered map
+ * @return the filtered map.
+ */
+ private Map<String, String> applyFilters(Map<String, String> inputMap) {
+ // Apply filters to values, prevent values filtered to null!
+ for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
+ AtomicInteger changes = new AtomicInteger();
+ for (PropertyFilter filter : getConfigurationContext().getPropertyFilters()) {
+ inputMap.replaceAll((k, v) -> {
+ String newValue = filter.filterProperty(k, v);
+ if (newValue != null && !newValue.equals(v)) {
+ changes.incrementAndGet();
+ LOG.finest(() -> "Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
+ } else if (v != null && !v.equals(newValue)) {
+ changes.incrementAndGet();
+ LOG.finest(() -> "Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
+ }
+ return newValue;
+ });
+ }
+ if (changes.get() == 0) {
+ LOG.finest(() -> "Finishing filter loop, no changes detected.");
+ break;
+ } else {
+ if (i == (MAX_FILTER_LOOPS - 1)) {
+ if (LOG.isLoggable(Level.WARNING)) {
+ LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
+ }
+ } else {
+ LOG.finest(() -> "Repeating filter loop, changes detected: " + changes.get());
+ }
+ changes.set(0);
+ }
+ }
+ // Remove null values
+ return inputMap.entrySet().parallelStream().filter((e) -> e.getValue() != null).collect(
+ Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));
+ }
+
+ /**
+ * Accesses the current String value for the given key (see {@link #getOptional(String)}) and tries to convert it
+ * using the {@link org.apache.tamaya.PropertyConverter} instances provided by the current
+ * {@link org.apache.tamaya.spi.ConfigurationContext}.
+ *
+ * @param key the property's absolute, or relative path, e.g. @code
+ * a/b/c/d.myProperty}.
+ * @param type The target type required, not null.
+ * @param <T> the value type
+ * @return the converted value, never null.
+ */
+ @Override
+ public <T> T get(String key, TypeLiteral<T> type) {
+ Optional<String> value = getOptional(key);
+ if (value.isPresent()) {
+ List<PropertyConverter<T>> converters = getConfigurationContext().getPropertyConverters(type);
+ for (PropertyConverter<T> converter : converters) {
+ try {
+ T t = converter.convert(value.get());
+ if (t != null) {
+ return t;
+ }
+ } catch (Exception e) {
+ LOG.log(Level.FINEST, e, () -> "PropertyConverter: " + converter +
+ " failed to convert value: " + value.get());
+ }
+ }
+ throw new ConfigException("Unparseable config value for type: " + type.getType() + ": " + key);
+ }
+
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfigurationContext.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfigurationContext.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfigurationContext.java
index d299ca4..0d6c171 100644
--- a/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfigurationContext.java
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/BaseConfigurationContext.java
@@ -18,7 +18,23 @@
*/
package org.apache.tamaya.core.internal;
+import org.apache.tamaya.PropertyConverter;
+import org.apache.tamaya.TypeLiteral;
import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertyFilter;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spi.ServiceContext;
+
+import javax.annotation.Priority;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.StampedLock;
/**
* Base class for all implementations of {@code ConfigurationContext}.
@@ -26,5 +42,130 @@ import org.apache.tamaya.spi.ConfigurationContext;
* @see ConfigurationContext
*/
public abstract class BaseConfigurationContext
- implements ConfigurationContext {
+ implements ConfigurationContext {
+
+ /**
+ * Subcomponent handling {@link org.apache.tamaya.PropertyConverter}
+ * instances.
+ */
+ private PropertyConverterManager propertyConverterManager = new PropertyConverterManager();
+
+ /**
+ * The current unmodifiable list of loaded {@link org.apache.tamaya.spi.PropertySource}
+ * instances.
+ */
+ private List<PropertySource> immutablePropertySources;
+
+ /**
+ * The current unmodifiable list of loaded {@link org.apache.tamaya.spi.PropertyFilter}
+ * instances.
+ */
+ private List<PropertyFilter> immutablePropertyFilters;
+
+ /**
+ * Lock for internal synchronization.
+ */
+ private StampedLock propertySourceLock = new StampedLock();
+
+ /**
+ * Pick up all {@link org.apache.tamaya.spi.PropertySourceProvider}s and
+ * return all the {@link org.apache.tamaya.spi.PropertySource}s they like to
+ * register.
+ */
+ protected Collection<? extends PropertySource> evaluatePropertySourcesFromProviders() {
+ List<PropertySource> propertySources = new ArrayList<>();
+ List<PropertySourceProvider> propertySourceProviders = ServiceContext.getInstance().getServices(PropertySourceProvider.class);
+ for (PropertySourceProvider propertySourceProvider : propertySourceProviders) {
+ propertySources.addAll(propertySourceProvider.getPropertySources());
+ }
+
+ return propertySources;
+ }
+
+ @Override
+ public void addPropertySources(PropertySource... propertySourcesToAdd) {
+ Lock writeLock = propertySourceLock.asWriteLock();
+ try {
+ writeLock.lock();
+ List<PropertySource> newPropertySources = new ArrayList<>(this.immutablePropertySources);
+ newPropertySources.addAll(Arrays.asList(propertySourcesToAdd));
+ Collections.sort(newPropertySources, this::comparePropertySources);
+
+ this.immutablePropertySources = Collections.unmodifiableList(newPropertySources);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Order property source reversely, the most important come first.
+ *
+ * @param source1 the first PropertySource
+ * @param source2 the second PropertySource
+ * @return the comparison result.
+ */
+ protected int comparePropertySources(PropertySource source1, PropertySource source2) {
+ if (source1.getOrdinal() < source2.getOrdinal()) {
+ return 1;
+ } else if (source1.getOrdinal() > source2.getOrdinal()) {
+ return -1;
+ } else {
+ return source2.getClass().getName().compareTo(source1.getClass().getName());
+ }
+ }
+
+ /**
+ * Compare 2 filters for ordering the filter chain.
+ *
+ * @param filter1 the first filter
+ * @param filter2 the second filter
+ * @return the comparison result
+ */
+ protected int comparePropertyFilters(PropertyFilter filter1, PropertyFilter filter2) {
+ Priority prio1 = filter1.getClass().getAnnotation(Priority.class);
+ Priority prio2 = filter2.getClass().getAnnotation(Priority.class);
+ int ord1 = prio1 != null ? prio1.value() : 0;
+ int ord2 = prio2 != null ? prio2.value() : 0;
+
+ if (ord1 < ord2) {
+ return -1;
+ } else if (ord1 > ord2) {
+ return 1;
+ } else {
+ return filter1.getClass().getName().compareTo(filter2.getClass().getName());
+ }
+ }
+
+ @Override
+ public List<PropertySource> getPropertySources() {
+ return immutablePropertySources;
+ }
+
+ @Override
+ public <T> void addPropertyConverter(TypeLiteral<T> typeToConvert, PropertyConverter<T> converter) {
+ propertyConverterManager.register(typeToConvert, converter);
+ }
+
+ @Override
+ public Map<TypeLiteral<?>, List<PropertyConverter<?>>> getPropertyConverters() {
+ return propertyConverterManager.getPropertyConverters();
+ }
+
+ @Override
+ public <T> List<PropertyConverter<T>> getPropertyConverters(TypeLiteral<T> type) {
+ return propertyConverterManager.getPropertyConverters(type);
+ }
+
+ @Override
+ public List<PropertyFilter> getPropertyFilters() {
+ return immutablePropertyFilters;
+ }
+
+ protected void setImmutablePropertySources(List<PropertySource> sources) {
+ immutablePropertySources = sources;
+ }
+
+ protected void setImmutablePropertyFilters(List<PropertyFilter> filter) {
+ immutablePropertyFilters = filter;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
index 60fcac5..be1ae81 100644
--- a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfiguration.java
@@ -18,40 +18,17 @@
*/
package org.apache.tamaya.core.internal;
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.TypeLiteral;
+
import org.apache.tamaya.spi.ConfigurationContext;
-import org.apache.tamaya.PropertyConverter;
-import org.apache.tamaya.spi.PropertyFilter;
-import org.apache.tamaya.spi.PropertySource;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
/**
* Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the
* chain of {@link org.apache.tamaya.spi.PropertySource} and {@link org.apache.tamaya.spi.PropertyFilter}
* instance to evaluate the current Configuration.
*/
-public class DefaultConfiguration implements Configuration {
- /**
- * The logger.
- */
- private static final Logger LOG = Logger.getLogger(DefaultConfiguration.class.getName());
- /**
- * The maximal number of filter cycles performed before aborting.
- */
- private static final int MAX_FILTER_LOOPS = 10;
+public class DefaultConfiguration extends BaseConfiguration {
/**
* The current {@link org.apache.tamaya.spi.ConfigurationContext} of the current instance.
@@ -62,171 +39,9 @@ public class DefaultConfiguration implements Configuration {
this.configurationContext = Objects.requireNonNull(context);
}
- /**
- * This method evaluates the given configuration key. Hereby if goes down the chain or PropertySource instances
- * provided by the current {@link org.apache.tamaya.spi.ConfigurationContext}. The first non-null-value returned
- * is taken as an intermediate value. Finally the value is filtered through the
- * {@link org.apache.tamaya.spi.PropertyFilter} instances installed, before it is returned as the final result of
- * this method.
- *
- * @param key the property's key, not null.
- * @return the optional configuration value, never null.
- */
- @Override
- public String get(String key) {
- List<PropertySource> propertySources = configurationContext.getPropertySources();
- String unfilteredValue = null;
- for (PropertySource propertySource : propertySources) {
- String value = propertySource.get(key);
- if (value != null) {
- unfilteredValue = value.length() > 0 ? value : null;
- break;
- }
- }
- return applyFilter(key, unfilteredValue);
- }
-
- /**
- * Apply filters to a single property value.
- *
- * @param key the key, used for logging, not null.
- * @param unfilteredValue the unfiltered property value.
- * @return the filtered value, or null.
- */
- private String applyFilter(String key, String unfilteredValue) {
- // Apply filters to values, prevent values filtered to null!
- for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
- boolean changed = false;
- // Apply filters to values, prevent values filtered to null!
- for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
- String newValue = filter.filterProperty(key, unfilteredValue);
- if (newValue != null && !newValue.equals(unfilteredValue)) {
- changed = true;
- if (LOG.isLoggable(Level.FINEST)) {
- LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
- }
- } else if (unfilteredValue != null && !unfilteredValue.equals(newValue)) {
- changed = true;
- if (LOG.isLoggable(Level.FINEST)) {
- LOG.finest("Filter - " + key + ": " + unfilteredValue + " -> " + newValue + " by " + filter);
- }
- }
- unfilteredValue = newValue;
- }
- if (!changed) {
- LOG.finest(() -> "Finishing filter loop, no changes detected.");
- break;
- } else {
- if (i == (MAX_FILTER_LOOPS - 1)) {
- if (LOG.isLoggable(Level.WARNING)) {
- LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
- }
- } else {
- LOG.finest(() -> "Repeating filter loop, changes detected.");
- }
- }
- }
- return unfilteredValue;
- }
- /**
- * Get the current properties, composed by the loaded {@link org.apache.tamaya.spi.PropertySource} and filtered
- * by registered {@link org.apache.tamaya.spi.PropertyFilter}.
- *
- * @return the final properties.
- */
- @Override
- public Map<String, String> getProperties() {
- List<PropertySource> propertySources = new ArrayList<>(configurationContext.getPropertySources());
- Collections.reverse(propertySources);
- Map<String, String> result = new HashMap<>();
- for (PropertySource propertySource : propertySources) {
- try {
- int origSize = result.size();
- Map<String, String> otherMap = propertySource.getProperties();
- LOG.log(Level.FINEST, null, () -> "Overriding with properties from " + propertySource.getName());
- result.putAll(otherMap);
- LOG.log(Level.FINEST, null, () -> "Handled properties from " + propertySource.getName() + "(new: " +
- (result.size() - origSize) + ", overrides: " + origSize + ", total: " + result.size());
- } catch (Exception e) {
- LOG.log(Level.SEVERE, "Error adding properties from PropertySource: " + propertySource + ", ignoring PropertySource.", e);
- }
- }
- return applyFilters(result);
- }
-
- /**
- * Filter a full configuration property map.
- *
- * @param inputMap the unfiltered map
- * @return the filtered map.
- */
- private Map<String, String> applyFilters(Map<String, String> inputMap) {
- // Apply filters to values, prevent values filtered to null!
- for (int i = 0; i < MAX_FILTER_LOOPS; i++) {
- AtomicInteger changes = new AtomicInteger();
- for (PropertyFilter filter : configurationContext.getPropertyFilters()) {
- inputMap.replaceAll((k, v) -> {
- String newValue = filter.filterProperty(k, v);
- if (newValue != null && !newValue.equals(v)) {
- changes.incrementAndGet();
- LOG.finest(() -> "Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
- } else if (v != null && !v.equals(newValue)) {
- changes.incrementAndGet();
- LOG.finest(() -> "Filter - " + k + ": " + v + " -> " + newValue + " by " + filter);
- }
- return newValue;
- });
- }
- if (changes.get() == 0) {
- LOG.finest(() -> "Finishing filter loop, no changes detected.");
- break;
- } else {
- if (i == (MAX_FILTER_LOOPS - 1)) {
- if (LOG.isLoggable(Level.WARNING)) {
- LOG.warning("Maximal filter loop count reached, aborting filter evaluation after cycles: " + i);
- }
- } else {
- LOG.finest(() -> "Repeating filter loop, changes detected: " + changes.get());
- }
- changes.set(0);
- }
- }
- // Remove null values
- return inputMap.entrySet().parallelStream().filter((e) -> e.getValue() != null).collect(
- Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));
- }
-
- /**
- * Accesses the current String value for the given key (see {@link #getOptional(String)}) and tries to convert it
- * using the {@link org.apache.tamaya.PropertyConverter} instances provided by the current
- * {@link org.apache.tamaya.spi.ConfigurationContext}.
- *
- * @param key the property's absolute, or relative path, e.g. @code
- * a/b/c/d.myProperty}.
- * @param type The target type required, not null.
- * @param <T> the value type
- * @return the converted value, never null.
- */
@Override
- public <T> T get(String key, TypeLiteral<T> type) {
- Optional<String> value = getOptional(key);
- if (value.isPresent()) {
- List<PropertyConverter<T>> converters = configurationContext.getPropertyConverters(type);
- for (PropertyConverter<T> converter : converters) {
- try {
- T t = converter.convert(value.get());
- if (t != null) {
- return t;
- }
- } catch (Exception e) {
- LOG.log(Level.FINEST, e, () -> "PropertyConverter: " + converter +
- " failed to convert value: " + value.get());
- }
- }
- throw new ConfigException("Unparseable config value for type: " + type.getType() + ": " + key);
- }
-
- return null;
+ protected ConfigurationContext getConfigurationContext() {
+ return configurationContext;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java
index 6f853af..ffd3724 100644
--- a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultConfigurationContext.java
@@ -18,48 +18,18 @@
*/
package org.apache.tamaya.core.internal;
-import org.apache.tamaya.TypeLiteral;
-import org.apache.tamaya.spi.ConfigurationContext;
-import org.apache.tamaya.PropertyConverter;
import org.apache.tamaya.spi.PropertyFilter;
import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertySourceProvider;
import org.apache.tamaya.spi.ServiceContext;
-import javax.annotation.Priority;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.StampedLock;
/**
* Default Implementation of a simple ConfigurationContext.
*/
public class DefaultConfigurationContext extends BaseConfigurationContext {
- /**
- * Subcomponent handling {@link org.apache.tamaya.PropertyConverter} instances.
- */
- private PropertyConverterManager propertyConverterManager = new PropertyConverterManager();
-
- /**
- * The current unmodifiable list of loaded {@link org.apache.tamaya.spi.PropertySource} instances.
- */
- private List<PropertySource> immutablePropertySources;
-
- /**
- * The current unmodifiable list of loaded {@link org.apache.tamaya.spi.PropertyFilter} instances.
- */
- private List<PropertyFilter> immutablePropertyFilters;
-
- /**
- * Lock for internal synchronization.
- */
- private StampedLock propertySourceLock = new StampedLock();
-
/**
* The first time the Configuration system gets invoked we do initialize
@@ -78,107 +48,14 @@ public class DefaultConfigurationContext extends BaseConfigurationContext {
// now sort them according to their ordinal values
Collections.sort(propertySources, this::comparePropertySources);
- immutablePropertySources = Collections.unmodifiableList(propertySources);
+ setImmutablePropertySources(Collections.unmodifiableList(propertySources));
// as next step we pick up the PropertyFilters pretty much the same way
List<PropertyFilter> propertyFilters = new ArrayList<>();
propertyFilters.addAll(ServiceContext.getInstance().getServices(PropertyFilter.class));
Collections.sort(propertyFilters, this::comparePropertyFilters);
- immutablePropertyFilters = Collections.unmodifiableList(propertyFilters);
- }
-
- /**
- * Pick up all {@link org.apache.tamaya.spi.PropertySourceProvider}s and return all the
- * {@link org.apache.tamaya.spi.PropertySource}s they like to register.
- */
- private Collection<? extends PropertySource> evaluatePropertySourcesFromProviders() {
- List<PropertySource> propertySources = new ArrayList<>();
- List<PropertySourceProvider> propertySourceProviders = ServiceContext.getInstance().getServices(PropertySourceProvider.class);
- for (PropertySourceProvider propertySourceProvider : propertySourceProviders) {
- propertySources.addAll(propertySourceProvider.getPropertySources());
- }
-
- return propertySources;
- }
-
- @Override
- public void addPropertySources(PropertySource... propertySourcesToAdd) {
- Lock writeLock = propertySourceLock.asWriteLock();
- try {
- writeLock.lock();
- List<PropertySource> newPropertySources = new ArrayList<>(this.immutablePropertySources);
- newPropertySources.addAll(Arrays.asList(propertySourcesToAdd));
- Collections.sort(newPropertySources, this::comparePropertySources);
-
- this.immutablePropertySources = Collections.unmodifiableList(newPropertySources);
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * Order property source reversely, the most important come first.
- *
- * @param source1 the first PropertySource
- * @param source2 the second PropertySource
- * @return the comparison result.
- */
- private int comparePropertySources(PropertySource source1, PropertySource source2) {
- if (source1.getOrdinal() < source2.getOrdinal()) {
- return 1;
- } else if (source1.getOrdinal() > source2.getOrdinal()) {
- return -1;
- } else {
- return source2.getClass().getName().compareTo(source1.getClass().getName());
- }
- }
-
- /**
- * Compare 2 filters for ordering the filter chain.
- *
- * @param filter1 the first filter
- * @param filter2 the second filter
- * @return the comparison result
- */
- private int comparePropertyFilters(PropertyFilter filter1, PropertyFilter filter2) {
- Priority prio1 = filter1.getClass().getAnnotation(Priority.class);
- Priority prio2 = filter2.getClass().getAnnotation(Priority.class);
- int ord1 = prio1 != null ? prio1.value() : 0;
- int ord2 = prio2 != null ? prio2.value() : 0;
-
- if (ord1 < ord2) {
- return -1;
- } else if (ord1 > ord2) {
- return 1;
- } else {
- return filter1.getClass().getName().compareTo(filter2.getClass().getName());
- }
- }
-
- @Override
- public List<PropertySource> getPropertySources() {
- return immutablePropertySources;
- }
-
- @Override
- public <T> void addPropertyConverter(TypeLiteral<T> typeToConvert, PropertyConverter<T> propertyConverter) {
- propertyConverterManager.register(typeToConvert, propertyConverter);
- }
-
- @Override
- public Map<TypeLiteral<?>, List<PropertyConverter<?>>> getPropertyConverters() {
- return propertyConverterManager.getPropertyConverters();
- }
-
- @Override
- public <T> List<PropertyConverter<T>> getPropertyConverters(TypeLiteral<T> targetType) {
- return propertyConverterManager.getPropertyConverters(targetType);
- }
-
- @Override
- public List<PropertyFilter> getPropertyFilters() {
- return immutablePropertyFilters;
+ setImmutablePropertyFilters(Collections.unmodifiableList(propertyFilters));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/modules/builder/pom.xml
----------------------------------------------------------------------
diff --git a/modules/builder/pom.xml b/modules/builder/pom.xml
index 5b37004..6ec1891 100644
--- a/modules/builder/pom.xml
+++ b/modules/builder/pom.xml
@@ -40,6 +40,13 @@ under the License.
<artifactId>tamaya-api</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.tamaya</groupId>
+ <artifactId>tamaya-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/modules/builder/src/main/java/org/apache/tamaya/builder/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/ConfigurationBuilder.java b/modules/builder/src/main/java/org/apache/tamaya/builder/ConfigurationBuilder.java
index 02a20ab..04d0e8f 100644
--- a/modules/builder/src/main/java/org/apache/tamaya/builder/ConfigurationBuilder.java
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/ConfigurationBuilder.java
@@ -21,21 +21,45 @@ package org.apache.tamaya.builder;
import org.apache.tamaya.Configuration;
import org.apache.tamaya.PropertyConverter;
import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.spi.ConfigurationContext;
import org.apache.tamaya.spi.PropertyFilter;
import org.apache.tamaya.spi.PropertySource;
import org.apache.tamaya.spi.PropertySourceProvider;
import org.apache.tamaya.spi.PropertyValueCombinationPolicy;
+import java.util.Objects;
+
/**
* Builder that allows to build a Configuration completely manually.
*/
public class ConfigurationBuilder {
+ /**
+ * Flag to indicate if this builder instance has already been used
+ * to build a configuration.
+ */
+ private boolean burned = false;
+
+ private ConfigurationContext context = new ProgrammaticConfigurationContext();
+
+ /**
+ * Allows to set configuration context during unit tests.
+ */
+ ConfigurationBuilder setConfigurationContext(ConfigurationContext configurationContext) {
+ context = configurationContext;
+
+ return this;
+ }
+
+ public ConfigurationBuilder addPropertySources(PropertySource... sources){
+ Objects.requireNonNull(sources);
+
+ context.addPropertySources(sources);
- public ConfigurationBuilder addPropertySources(PropertySource... propertySources){
return this;
}
public ConfigurationBuilder addPropertySourceProviders(PropertySourceProvider... propertySourceProviders){
+
return this;
}
@@ -48,6 +72,7 @@ public class ConfigurationBuilder {
}
public ConfigurationBuilder addPropertyConverter(PropertyConverter<?> propertyConverter){
+
return this;
}
@@ -56,6 +81,15 @@ public class ConfigurationBuilder {
}
public Configuration build() {
- return null;
+ checkStateOfBuilder();
+ burned = true;
+
+ return new ProgrammaticConfiguration(context);
+ }
+
+ private void checkStateOfBuilder() {
+ if (burned) {
+ throw new IllegalStateException("Configuration has been already build.");
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfiguration.java b/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfiguration.java
new file mode 100644
index 0000000..fc2df80
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * 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.builder;
+
+import org.apache.tamaya.core.internal.BaseConfiguration;
+import org.apache.tamaya.spi.ConfigurationContext;
+
+/**
+ * Implementation of the {@link org.apache.tamaya.spi.ConfigurationContext}
+ * used by the {@link org.apache.tamaya.builder.ConfigurationBuilder}
+ * internally.
+ */
+public class ProgrammaticConfiguration extends BaseConfiguration {
+ private final ConfigurationContext context;
+
+ public ProgrammaticConfiguration(ConfigurationContext configurationContext) {
+ context = configurationContext;
+ }
+
+ @Override
+ protected ConfigurationContext getConfigurationContext() {
+ return context;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfigurationContext.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfigurationContext.java b/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfigurationContext.java
new file mode 100644
index 0000000..bbe645b
--- /dev/null
+++ b/modules/builder/src/main/java/org/apache/tamaya/builder/ProgrammaticConfigurationContext.java
@@ -0,0 +1,32 @@
+/*
+ * 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.builder;
+
+
+import org.apache.tamaya.core.internal.BaseConfigurationContext;
+
+/**
+ * Implementation of the {@link org.apache.tamaya.ConfigurationContext}
+ * used by the {@link org.apache.tamaya.builder.ConfigurationBuilder}
+ * internally.
+ */
+public class ProgrammaticConfigurationContext
+ extends BaseConfigurationContext {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/cd93d8d2/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
----------------------------------------------------------------------
diff --git a/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java b/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
index d034391..de8d1fe 100644
--- a/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
+++ b/modules/builder/src/test/java/org/apache/tamaya/builder/ConfigurationBuilderTest.java
@@ -32,6 +32,22 @@ public class ConfigurationBuilderTest {
Configuration config = builder.build();
- // @todo assertThat(config, notNullValue());
+ assertThat(config, notNullValue());
}
+
+ @Test(expected = IllegalStateException.class)
+ public void buildCanBeCalledOnlyOnce() {
+ ConfigurationBuilder builder = new ConfigurationBuilder();
+
+ builder.build();
+ builder.build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void addPropertySourcesDoesNotAcceptNullValue() {
+ ConfigurationBuilder builder = new ConfigurationBuilder();
+
+ builder.addPropertySources(null);
+ }
+
}