/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.common.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; /** * In-memory Configuration implementation. */ public class MapConfiguration extends AbstractConfiguration { private static Logger log = LoggerFactory.getLogger(MapConfiguration.class); private Map<String, String> configMap; public MapConfiguration() { configMap = new ConcurrentHashMap<String, String>(); } public MapConfiguration(Map<String, String> configMap) { // ConcurrentHashMap doesn't work with null keys but HashMap // supports them. We have to check the type first because // ConcurrentHashMap will throw a NPE on containsKey(null) if (HashMap.class.isAssignableFrom(configMap.getClass()) && configMap.containsKey(null)) { log.error("Keys with a null value are not supported!"); throw new RuntimeException( new ConfigurationException("Keys with a null value are not supported")); } this.configMap = new ConcurrentHashMap<String, String>(configMap); } public MapConfiguration(Configuration config) { this(config.toMap()); } @Override public Configuration subset(String prefix) { return new MapConfiguration(subsetMap(prefix)); } @Override public Configuration strippedSubset(String prefix) { Map<String, String> subset = subsetMap(prefix); Configuration c = new MapConfiguration(); for (Map.Entry<String, String> entry : subset.entrySet()) { String strippedKey = entry.getKey().replaceFirst(Pattern.quote(prefix), ""); c.setProperty(strippedKey, entry.getValue()); } return c; } protected Map<String, String> subsetMap(String prefix) { Map<String, String> subset = new ConcurrentHashMap<String, String>(); for (Map.Entry<String, String> e : configMap.entrySet()) { // ConcurrentHashMaps do not allow null as a key but other // implementations do (HashMap) so we'll check to prevent // future bugs should the backing store change. if (e.getKey() != null && e.getKey().startsWith(prefix)) { subset.put(e.getKey(), e.getValue()); } } return subset; } /** * Merge configuration objects. Any collisions on keys will use the value * from the leftmost argument. * * @param configs * @return the merged configuration */ public static MapConfiguration merge(Configuration ... configs) { MapConfiguration mergedConfig = new MapConfiguration(); for (Configuration c : configs) { for (String key : c.getKeys()) { if (!mergedConfig.containsKey(key)) { mergedConfig.setProperty(key, c.getProperty(key)); } } } return mergedConfig; } @Override public boolean isEmpty() { return configMap.isEmpty(); } @Override public boolean containsKey(String key) { return (null == key) ? false : configMap.containsKey(key); } @Override public void setProperty(String key, String value) { configMap.put(key, value); } @Override public void clear() { configMap.clear(); } @Override public void clearProperty(String key) { configMap.remove(key); } @Override public Iterable<String> getKeys() { return configMap.keySet(); } @Override public String getProperty(String key) { if (containsKey(key)) { return configMap.get(key); } else { super.missingMessage(key); throw new NoSuchElementException(doesNotMapMessage(key)); } } @Override public String getProperty(String key, String defaultValue) { return (containsKey(key)) ? configMap.get(key) : defaultValue; } @Override public String toString() { return configMap.toString(); } }