/* * 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.ConfigurationProvider; import org.apache.tamaya.TypeLiteral; import org.apache.tamaya.spi.ConfigurationContext; import org.apache.tamaya.spi.ConfigurationContextBuilder; import org.apache.tamaya.spi.PropertyConverter; import org.apache.tamaya.spi.PropertyFilter; import org.apache.tamaya.spi.PropertySource; import org.apache.tamaya.spi.PropertyValue; import org.apache.tamaya.spi.PropertyValueCombinationPolicy; import org.apache.tamaya.spi.ServiceContextManager; import javax.annotation.Priority; import java.io.Serializable; import java.util.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Logger; /** * Default implementation of a simple ConfigurationContext. */ public class DefaultConfigurationContext implements ConfigurationContext { /** The logger used. */ private final static Logger LOG = Logger.getLogger(DefaultConfigurationContext.class.getName()); /** * Cubcomponent handling {@link org.apache.tamaya.spi.PropertyConverter} instances. */ private final 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 final ReentrantReadWriteLock propertySourceLock = new ReentrantReadWriteLock(); /** * Lock for internal synchronization. */ private final ReentrantReadWriteLock propertyFilterLock = new ReentrantReadWriteLock(); DefaultConfigurationContext(DefaultConfigurationContextBuilder builder) { List<PropertySource> propertySources = new ArrayList<>(); // first we load all PropertySources which got registered via java.util.ServiceLoader propertySources.addAll(builder.propertySources); // now sort them according to their ordinal values immutablePropertySources = Collections.unmodifiableList(propertySources); // as next step we pick up the PropertyFilters pretty much the same way List<PropertyFilter> propertyFilters = new ArrayList<>(builder.getPropertyFilters()); immutablePropertyFilters = Collections.unmodifiableList(propertyFilters); // Finally add the converters for(Map.Entry<TypeLiteral<?>, Collection<PropertyConverter<?>>> en:builder.getPropertyConverter().entrySet()) { for (PropertyConverter converter : en.getValue()) { this.propertyConverterManager.register(en.getKey(), converter); } } propertyValueCombinationPolicy = builder.combinationPolicy; if(propertyValueCombinationPolicy==null){ propertyValueCombinationPolicy = ServiceContextManager.getServiceContext().getService(PropertyValueCombinationPolicy.class); } if(propertyValueCombinationPolicy==null){ propertyValueCombinationPolicy = PropertyValueCombinationPolicy.DEFAULT_OVERRIDING_COLLECTOR; } } @Deprecated @Override public void addPropertySources(PropertySource... propertySourcesToAdd) { Lock writeLock = propertySourceLock.writeLock(); try { writeLock.lock(); List<PropertySource> newPropertySources = new ArrayList<>(this.immutablePropertySources); newPropertySources.addAll(Arrays.asList(propertySourcesToAdd)); Collections.sort(newPropertySources, PropertySourceComparator.getInstance()); this.immutablePropertySources = Collections.unmodifiableList(newPropertySources); } finally { writeLock.unlock(); } } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof DefaultConfigurationContext)) return false; DefaultConfigurationContext that = (DefaultConfigurationContext) o; if (!propertyConverterManager.equals(that.propertyConverterManager)) return false; if (!immutablePropertySources.equals(that.immutablePropertySources)) return false; if (!immutablePropertyFilters.equals(that.immutablePropertyFilters)) return false; return getPropertyValueCombinationPolicy().equals(that.getPropertyValueCombinationPolicy()); } @Override public int hashCode() { int result = propertyConverterManager.hashCode(); result = 31 * result + immutablePropertySources.hashCode(); result = 31 * result + immutablePropertyFilters.hashCode(); result = 31 * result + getPropertyValueCombinationPolicy().hashCode(); return result; } @Override public String toString() { StringBuilder b = new StringBuilder("ConfigurationContext{\n"); b.append(" Property Sources\n"); b.append(" ----------------\n"); if(immutablePropertySources.isEmpty()){ b.append(" No property sources loaded.\n\n"); }else { b.append(" CLASS NAME SCANNABLE SIZE STATE ERROR\n\n"); for (PropertySource ps : immutablePropertySources) { b.append(" "); appendFormatted(b, ps.getClass().getSimpleName(), 30); appendFormatted(b, ps.getName(), 70); appendFormatted(b, String.valueOf(ps.isScannable()), 10); if (ps.isScannable()) { appendFormatted(b, String.valueOf(ps.getProperties().size()), 8); } else { appendFormatted(b, "-", 8); } PropertyValue state = ps.get("_state"); if(state==null){ appendFormatted(b, "OK", 10); }else { appendFormatted(b, state.getValue(), 10); if("ERROR".equals(state.getValue())){ PropertyValue val = ps.get("_exception"); if(val!=null) { appendFormatted(b, val.getValue(), 30); } } } b.append('\n'); } b.append("\n"); } b.append(" Property Filters\n"); b.append(" ----------------\n"); if(immutablePropertyFilters.isEmpty()){ b.append(" No property filters loaded.\n\n"); }else { b.append(" CLASS INFO\n\n"); for (PropertyFilter filter : getPropertyFilters()) { b.append(" "); appendFormatted(b, filter.getClass().getSimpleName(), 30); b.append(removeNewLines(filter.toString())); b.append('\n'); } b.append("\n\n"); } b.append(" Property Converters\n"); b.append(" -------------------\n"); b.append(" CLASS TYPE INFO\n\n"); for(Map.Entry<TypeLiteral<?>, List<PropertyConverter<?>>> converterEntry:getPropertyConverters().entrySet()){ for(PropertyConverter converter: converterEntry.getValue()){ b.append(" "); appendFormatted(b, converter.getClass().getSimpleName(), 30); appendFormatted(b, converterEntry.getKey().getRawType().getSimpleName(), 30); b.append(removeNewLines(converter.toString())); b.append('\n'); } } b.append("\n\n"); b.append(" PropertyValueCombinationPolicy: ").append(getPropertyValueCombinationPolicy().getClass().getName()).append('\n'); b.append('}'); return b.toString(); } private void appendFormatted(StringBuilder b, String text, int length) { int padding; if(text.length() <= (length)){ b.append(text); padding = length - text.length(); }else{ b.append(text.substring(0, length-1)); padding = 1; } for(int i=0;i<padding;i++){ b.append(' '); } } private String removeNewLines(String s) { return s.replace('\n', ' ').replace('\r', ' '); } @Override public List<PropertySource> getPropertySources() { return immutablePropertySources; } @Override public PropertySource getPropertySource(String name) { for(PropertySource ps:getPropertySources()){ if(name.equals(ps.getName())){ return ps; } } return null; } @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; } @Override public ConfigurationContextBuilder toBuilder() { return ConfigurationProvider.getConfigurationContextBuilder().setContext(this); } }