TAMAYA-63: Aligned API with Java 7. Fixed issues. TAMAYA 61: Implemented value combination interface logic.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/3520c835 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/3520c835 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/3520c835 Branch: refs/heads/master Commit: 3520c835a54a8f4b6c5e21e1109e9bb3b9cbb22b Parents: a95b0ba Author: anatole <anat...@apache.org> Authored: Sun Jan 25 23:43:15 2015 +0100 Committer: anatole <anat...@apache.org> Committed: Mon Jan 26 00:33:42 2015 +0100 ---------------------------------------------------------------------- .../java/org/apache/tamaya/Configuration.java | 26 +++ .../apache/tamaya/spi/ConfigurationContext.java | 6 + .../spi/PropertyValueCombinationPolicy.java | 2 +- .../core/internal/DefaultConfiguration.java | 200 ++++++++++++++++++- .../internal/DefaultConfigurationContext.java | 165 ++++++++++++++- .../services/org.apache.tamaya.Configuration | 19 -- .../org.apache.tamaya.spi.ConfigurationContext | 19 -- 7 files changed, 388 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/java8/api/src/main/java/org/apache/tamaya/Configuration.java ---------------------------------------------------------------------- diff --git a/java8/api/src/main/java/org/apache/tamaya/Configuration.java b/java8/api/src/main/java/org/apache/tamaya/Configuration.java index 4ee7f21..3b81775 100644 --- a/java8/api/src/main/java/org/apache/tamaya/Configuration.java +++ b/java8/api/src/main/java/org/apache/tamaya/Configuration.java @@ -19,6 +19,7 @@ package org.apache.tamaya; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; @@ -109,6 +110,31 @@ public interface Configuration { } /** + * Get the property keys as type {@code Class<T>}. + * <p> + * If {@code Class<T>} is not one current + * {@code Boolean, Short, Integer, Long, Float, Double, BigInteger, + * BigDecimal, String} , an according converter must be + * available to perform the conversion fromMap {@link String} to + * {@code Class<T>}. + * + * @param key the property's absolute, or relative path, e.g. @code + * a/b/c/d.myProperty}. + * @param converter the PropertyConverter to perform the conversion fromMap + * {@link String} to {@code Class<T>}, not {@code null}. + * @return the property's keys. + * @throws ConfigException if the keys could not be converted to the required target + * type, or no such property exists. + */ + default <T> T get(String key, PropertyConverter<T> converter) { + String value = get(key); + if (value!=null) { + return Objects.requireNonNull(converter).convert(value); + } + return null; + } + + /** * Access all current known Configuration properties as a full {@code Map<String,String>}. * Be aware that entries from non scannable parts of the registered {@link org.apache.tamaya.spi.PropertySource} * instances may not be contained in the result, but nevertheless be accessible calling one of the http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/java8/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java ---------------------------------------------------------------------- diff --git a/java8/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java b/java8/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java index 1848428..b7cd843 100644 --- a/java8/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java +++ b/java8/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java @@ -141,4 +141,10 @@ public interface ConfigurationContext { */ List<PropertyFilter> getPropertyFilters(); + /** + * Access the {@link org.apache.tamaya.spi.PropertyValueCombinationPolicy} used to evaluate the final + * property values. + * @return the {@link org.apache.tamaya.spi.PropertyValueCombinationPolicy} used, never null. + */ + PropertyValueCombinationPolicy getPropertyValueCombinationPolicy(); } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/java8/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java ---------------------------------------------------------------------- diff --git a/java8/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/java8/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java index 660cc11..ffc2bd7 100644 --- a/java8/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java +++ b/java8/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java @@ -35,7 +35,7 @@ public interface PropertyValueCombinationPolicy { * entry evaluated by {@code propertySource.get(key)}. */ public final PropertyValueCombinationPolicy DEFAULT_OVERRIDING_COLLECTOR = (current, key, propertySource) -> - Optional.ofNullable(propertySource.get(key)).orElse(current); + Optional.ofNullable(propertySource.get(key)).filter(s -> !s.isEmpty()).orElse(current); /** * Method that is called for each value evaluated by a PropertySource for the given key. This method is called http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/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 be1ae81..ee827b7 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,30 +18,218 @@ */ 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 org.apache.tamaya.spi.PropertyValueCombinationPolicy; +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 extends BaseConfiguration { +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; /** * The current {@link org.apache.tamaya.spi.ConfigurationContext} of the current instance. */ private final ConfigurationContext configurationContext; - public DefaultConfiguration(ConfigurationContext context){ - this.configurationContext = Objects.requireNonNull(context); + /** + * Constructor. + * @param configurationContext The configuration Context to be used. + */ + public DefaultConfiguration(ConfigurationContext configurationContext){ + this.configurationContext = Objects.requireNonNull(configurationContext); } + /** + * 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; + PropertyValueCombinationPolicy combinationPolicy = this.configurationContext + .getPropertyValueCombinationPolicy(); + for (PropertySource propertySource : propertySources) { + unfilteredValue = combinationPolicy.collect(unfilteredValue, key, propertySource); + } + 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 - protected ConfigurationContext getConfigurationContext() { - return configurationContext; + 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; } } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/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 ffd3724..44376a4 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,18 +18,61 @@ */ 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.PropertyValueCombinationPolicy; import org.apache.tamaya.spi.ServiceContext; +import javax.annotation.Priority; +import javax.xml.ws.Service; 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.StringJoiner; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.StampedLock; +import java.util.function.Function; +import java.util.logging.Logger; /** * Default Implementation of a simple ConfigurationContext. */ -public class DefaultConfigurationContext extends BaseConfigurationContext { +public class DefaultConfigurationContext implements ConfigurationContext { + /** The logger used. */ + private final static Logger LOG = Logger.getLogger(DefaultConfigurationContext.class.getName()); + /** + * Cubcomponent 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; + + /** + * The overriding policy used when combining PropertySources registered to evalute the final configuration + * values. + */ + private PropertyValueCombinationPolicy propertyValueCombinationPolicy; + + /** + * Lock for internal synchronization. + */ + private StampedLock propertySourceLock = new StampedLock(); + /** * The first time the Configuration system gets invoked we do initialize @@ -47,15 +90,129 @@ public class DefaultConfigurationContext extends BaseConfigurationContext { // now sort them according to their ordinal values Collections.sort(propertySources, this::comparePropertySources); - - setImmutablePropertySources(Collections.unmodifiableList(propertySources)); + immutablePropertySources = Collections.unmodifiableList(propertySources); + LOG.info(() -> "Registered " + immutablePropertySources.size() + " property sources: " + + createStringList(immutablePropertySources,ps -> ps.getName() + '[' + ps.getClass().getName()+']')); // 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); + LOG.info(() -> "Registered " + immutablePropertyFilters.size() + " property filters: " + + createStringList(immutablePropertyFilters,f -> f.getClass().getName())); + + propertyValueCombinationPolicy = ServiceContext.getInstance().getService(PropertyValueCombinationPolicy.class) + .orElse(PropertyValueCombinationPolicy.DEFAULT_OVERRIDING_COLLECTOR); + LOG.info(() -> "Using PropertyValueCombinationPolicy: " + propertyValueCombinationPolicy); + } + + /** + * 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) { + Collection<PropertySource> sources = propertySourceProvider.getPropertySources(); + LOG.finer(() -> "PropertySourceProvider " + propertySourceProvider.getClass().getName() + + " provided the following property sources: " + + createStringList(sources,ps -> ps.getName() + '[' + ps.getClass().getName()+']')); + propertySources.addAll(sources); + } + 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 source1.getClass().getName().compareTo(source2.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); + LOG.info(() -> "Added PropertyConverter: " + propertyConverter.getClass().getName()); + } + + @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; + } + + @Override + public PropertyValueCombinationPolicy getPropertyValueCombinationPolicy(){ + return propertyValueCombinationPolicy; + } - setImmutablePropertyFilters(Collections.unmodifiableList(propertyFilters)); + private <T> String createStringList(Collection<T> propertySources, Function<T,String> mapper){ + StringJoiner joiner = new StringJoiner(", "); + propertySources.forEach(t -> joiner.add(mapper.apply(t))); + return joiner.toString(); } } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration ---------------------------------------------------------------------- diff --git a/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration b/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration deleted file mode 100644 index 0db8402..0000000 --- a/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.Configuration +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy current 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. -# -org.apache.tamaya.core.internal.DefaultConfiguration \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/3520c835/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext ---------------------------------------------------------------------- diff --git a/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext b/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext deleted file mode 100644 index 32b4302..0000000 --- a/java8/core/src/main/resources/META-INF/services/org.apache.tamaya.spi.ConfigurationContext +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy current 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. -# -org.apache.tamaya.core.internal.DefaultConfigurationContext \ No newline at end of file