001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.configuration; 019 020 import java.util.ArrayList; 021 import java.util.Collection; 022 import java.util.Iterator; 023 import java.util.LinkedHashMap; 024 import java.util.List; 025 import java.util.Map; 026 027 /** 028 * Basic configuration class. Stores the configuration data but does not 029 * provide any load or save functions. If you want to load your Configuration 030 * from a file use PropertiesConfiguration or XmlConfiguration. 031 * 032 * This class extends normal Java properties by adding the possibility 033 * to use the same key many times concatenating the value strings 034 * instead of overwriting them. 035 * 036 * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> 037 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 038 * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a> 039 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> 040 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a> 041 * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a> 042 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 043 * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a> 044 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 045 * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a> 046 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 047 * @author <a href="mailto:ksh@scand.com">Konstantin Shaposhnikov</a> 048 * @version $Id: BaseConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $ 049 */ 050 public class BaseConfiguration extends AbstractConfiguration implements Cloneable 051 { 052 /** stores the configuration key-value pairs */ 053 private Map<String, Object> store = new LinkedHashMap<String, Object>(); 054 055 /** 056 * Adds a key/value pair to the map. This routine does no magic morphing. 057 * It ensures the keylist is maintained 058 * 059 * @param key key to use for mapping 060 * @param value object to store 061 */ 062 @Override 063 protected void addPropertyDirect(String key, Object value) 064 { 065 Object previousValue = getProperty(key); 066 067 if (previousValue == null) 068 { 069 store.put(key, value); 070 } 071 else if (previousValue instanceof List) 072 { 073 // safe to case because we have created the lists ourselves 074 @SuppressWarnings("unchecked") 075 List<Object> valueList = (List<Object>) previousValue; 076 // the value is added to the existing list 077 valueList.add(value); 078 } 079 else 080 { 081 // the previous value is replaced by a list containing the previous value and the new value 082 List<Object> list = new ArrayList<Object>(); 083 list.add(previousValue); 084 list.add(value); 085 086 store.put(key, list); 087 } 088 } 089 090 /** 091 * Read property from underlying map. 092 * 093 * @param key key to use for mapping 094 * 095 * @return object associated with the given configuration key. 096 */ 097 public Object getProperty(String key) 098 { 099 return store.get(key); 100 } 101 102 /** 103 * Check if the configuration is empty 104 * 105 * @return {@code true} if Configuration is empty, 106 * {@code false} otherwise. 107 */ 108 public boolean isEmpty() 109 { 110 return store.isEmpty(); 111 } 112 113 /** 114 * check if the configuration contains the key 115 * 116 * @param key the configuration key 117 * 118 * @return {@code true} if Configuration contain given key, 119 * {@code false} otherwise. 120 */ 121 public boolean containsKey(String key) 122 { 123 return store.containsKey(key); 124 } 125 126 /** 127 * Clear a property in the configuration. 128 * 129 * @param key the key to remove along with corresponding value. 130 */ 131 @Override 132 protected void clearPropertyDirect(String key) 133 { 134 if (containsKey(key)) 135 { 136 store.remove(key); 137 } 138 } 139 140 @Override 141 public void clear() 142 { 143 fireEvent(EVENT_CLEAR, null, null, true); 144 store.clear(); 145 fireEvent(EVENT_CLEAR, null, null, false); 146 } 147 148 /** 149 * Get the list of the keys contained in the configuration 150 * repository. 151 * 152 * @return An Iterator. 153 */ 154 public Iterator<String> getKeys() 155 { 156 return store.keySet().iterator(); 157 } 158 159 /** 160 * Creates a copy of this object. This implementation will create a deep 161 * clone, i.e. the map that stores the properties is cloned, too. So changes 162 * performed at the copy won't affect the original and vice versa. 163 * 164 * @return the copy 165 * @since 1.3 166 */ 167 @Override 168 public Object clone() 169 { 170 try 171 { 172 BaseConfiguration copy = (BaseConfiguration) super.clone(); 173 // This is safe because the type of the map is known 174 @SuppressWarnings("unchecked") 175 Map<String, Object> clonedStore = (Map<String, Object>) ConfigurationUtils.clone(store); 176 copy.store = clonedStore; 177 178 // Handle collections in the map; they have to be cloned, too 179 for (Map.Entry<String, Object> e : store.entrySet()) 180 { 181 if (e.getValue() instanceof Collection) 182 { 183 // This is safe because the collections were created by ourselves 184 @SuppressWarnings("unchecked") 185 Collection<String> strList = (Collection<String>) e.getValue(); 186 copy.store.put(e.getKey(), new ArrayList<String>(strList)); 187 } 188 } 189 190 return copy; 191 } 192 catch (CloneNotSupportedException cex) 193 { 194 // should not happen 195 throw new ConfigurationRuntimeException(cex); 196 } 197 } 198 }