/* * 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.ConfigOperator; import org.apache.tamaya.ConfigQuery; import org.apache.tamaya.Configuration; import org.apache.tamaya.TypeLiteral; import org.apache.tamaya.spi.*; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; /** * Implementation of the Configuration API. This class uses the current {@link ConfigurationContext} to evaluate the * chain of {@link PropertySource} and {@link 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 current {@link ConfigurationContext} of the current instance. */ private final ConfigurationContext configurationContext; /** * EvaluationStrategy */ private ConfigValueEvaluator configEvaluator = loadConfigValueEvaluator(); private ConfigValueEvaluator loadConfigValueEvaluator() { ConfigValueEvaluator eval = null; try{ eval = ServiceContextManager.getServiceContext() .getService(ConfigValueEvaluator.class); }catch(Exception e){ LOG.log(Level.WARNING, "Failed to load ConfigValueEvaluator from ServiceContext, using default.", e); } if(eval==null){ eval = new DefaultConfigValueEvaluator(); } return eval; } /** * Constructor. * @param configurationContext The configuration Context to be used. */ public DefaultConfiguration(ConfigurationContext configurationContext){ this.configurationContext = Objects.requireNonNull(configurationContext); } @Override public String get(String key) { Objects.requireNonNull(key, "Key must not be null."); PropertyValue value = configEvaluator.evaluteRawValue(key, configurationContext); if(value==null || value.getValue()==null){ return null; } value = PropertyFiltering.applyFilter(value, configurationContext); if(value!=null){ return value.getValue(); } return null; } @Override public String getOrDefault(String key, String defaultValue) { Objects.requireNonNull(key, "Key must not be null."); Objects.requireNonNull(defaultValue, "Default value must not be null"); String val = get(key); if(val==null){ return defaultValue; } return val; } @Override public <T> T getOrDefault(String key, Class<T> type, T defaultValue) { Objects.requireNonNull(key, "Key must not be null."); Objects.requireNonNull(type, "Target type must not be null"); Objects.requireNonNull(defaultValue, "Default value must not be null"); T val = get(key, type); if(val==null){ return defaultValue; } return val; } /** * Get the current properties, composed by the loaded {@link PropertySource} and filtered * by registered {@link PropertyFilter}. * * @return the final properties. */ @Override public Map<String, String> getProperties() { Map<String, PropertyValue> filtered = PropertyFiltering.applyFilters( configEvaluator.evaluateRawValues(configurationContext), configurationContext); Map<String,String> result = new HashMap<>(); for(PropertyValue val:filtered.values()){ if(val.getValue()!=null) { result.put(val.getKey(), val.getValue()); // TODO: Discuss metadata handling... result.putAll(val.getMetaEntries()); } } return result; } /** * Accesses the current String value for the given key and tries to convert it * using the {@link PropertyConverter} instances provided by the current * {@link ConfigurationContext}. * * @param key the property's absolute, or relative path, e.g. @code * a/b/c/d.myProperty}, never {@code null}. * @param type The target type required, not {@code null}. * @param <T> the value type * @return the converted value, never {@code null}. */ @Override public <T> T get(String key, Class<T> type) { Objects.requireNonNull(key, "Key must not be null."); Objects.requireNonNull(type, "Target type must not be null"); return get(key, (TypeLiteral<T>)TypeLiteral.of(type)); } /** * Accesses the current String value for the given key and tries to convert it * using the {@link PropertyConverter} instances provided by the current * {@link 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 {@code null}. * @param <T> the value type * @return the converted value, never {@code null}. */ @Override public <T> T get(String key, TypeLiteral<T> type) { Objects.requireNonNull(key, "Key must not be null."); Objects.requireNonNull(type, "Target type must not be null"); return convertValue(key, get(key), type); } protected <T> T convertValue(String key, String value, TypeLiteral<T> type) { if (value != null) { List<PropertyConverter<T>> converters = configurationContext.getPropertyConverters(type); ConversionContext context = new ConversionContext.Builder(this, this.configurationContext, key, type) .build(); for (PropertyConverter<T> converter : converters) { try { T t = converter.convert(value, context); if (t != null) { return t; } } catch (Exception e) { LOG.log(Level.INFO, "PropertyConverter: " + converter + " failed to convert value: " + value, e); } } // if the target type is a String, we can return the value, no conversion required. if(type.equals(TypeLiteral.of(String.class))){ return (T)value; } // unsupported type, throw an exception throw new ConfigException("Unparseable config value for type: " + type.getRawType().getName() + ": " + key + ", supported formats: " + context.getSupportedFormats()); } return null; } @Override public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) { Objects.requireNonNull(key); Objects.requireNonNull(type); Objects.requireNonNull(defaultValue); T val = get(key, type); if(val==null){ return defaultValue; } return val; } @Override public Configuration with(ConfigOperator operator) { return operator.operate(this); } @Override public <T> T query(ConfigQuery<T> query) { return query.query(this); } @Override public ConfigurationContext getContext() { return this.configurationContext; } @Override public String toString() { return "Configuration{\n " + configurationContext + '}'; } }