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.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    
025    /**
026     * <p>A Map based Configuration.</p>
027     * <p><em>Note:</em>Configuration objects of this type can be read concurrently
028     * by multiple threads. However if one of these threads modifies the object,
029     * synchronization has to be performed manually.</p>
030     *
031     * @author Emmanuel Bourg
032     * @version $Revision: 548098 $, $Date: 2007-06-17 21:34:03 +0200 (So, 17 Jun 2007) $
033     * @since 1.1
034     */
035    public class MapConfiguration extends AbstractConfiguration implements Cloneable
036    {
037        /** The Map decorated by this configuration. */
038        protected Map map;
039    
040        /**
041         * Create a Configuration decorator around the specified Map. The map is
042         * used to store the configuration properties, any change will also affect
043         * the Map.
044         *
045         * @param map the map
046         */
047        public MapConfiguration(Map map)
048        {
049            this.map = map;
050        }
051    
052        /**
053         * Return the Map decorated by this configuration.
054         *
055         * @return the map this configuration is based onto
056         */
057        public Map getMap()
058        {
059            return map;
060        }
061    
062        public Object getProperty(String key)
063        {
064            Object value = map.get(key);
065            if ((value instanceof String) && (!isDelimiterParsingDisabled()))
066            {
067                List list = PropertyConverter.split((String) value, getListDelimiter());
068                return list.size() > 1 ? list : list.get(0);
069            }
070            else
071            {
072                return value;
073            }
074        }
075    
076        protected void addPropertyDirect(String key, Object value)
077        {
078            Object previousValue = getProperty(key);
079    
080            if (previousValue == null)
081            {
082                map.put(key, value);
083            }
084            else if (previousValue instanceof List)
085            {
086                // the value is added to the existing list
087                ((List) previousValue).add(value);
088            }
089            else
090            {
091                // the previous value is replaced by a list containing the previous value and the new value
092                List list = new ArrayList();
093                list.add(previousValue);
094                list.add(value);
095    
096                map.put(key, list);
097            }
098        }
099    
100        public boolean isEmpty()
101        {
102            return map.isEmpty();
103        }
104    
105        public boolean containsKey(String key)
106        {
107            return map.containsKey(key);
108        }
109    
110        protected void clearPropertyDirect(String key)
111        {
112            map.remove(key);
113        }
114    
115        public Iterator getKeys()
116        {
117            return map.keySet().iterator();
118        }
119    
120        /**
121         * Returns a copy of this object. The returned configuration will contain
122         * the same properties as the original. Event listeners are not cloned.
123         *
124         * @return the copy
125         * @since 1.3
126         */
127        public Object clone()
128        {
129            try
130            {
131                MapConfiguration copy = (MapConfiguration) super.clone();
132                copy.clearConfigurationListeners();
133                copy.map = (Map) ConfigurationUtils.clone(map);
134                return copy;
135            }
136            catch (CloneNotSupportedException cex)
137            {
138                // cannot happen
139                throw new ConfigurationRuntimeException(cex);
140            }
141        }
142    }