    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.List;
    024    import java.util.Map;
    025
    026    import org.apache.commons.collections.map.LinkedMap;
    027
    028    /**
    029     * Basic configuration class. Stores the configuration data but does not
    030     * provide any load or save functions. If you want to load your Configuration
    031     * from a file use PropertiesConfiguration or XmlConfiguration.
    032     *
    033     * This class extends normal Java properties by adding the possibility
    034     * to use the same key many times concatenating the value strings
    035     * instead of overwriting them.
    036     *
    037     * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
    038     * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
    039     * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
    040     * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
    041     * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
    042     * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
    043     * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
    044     * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
    045     * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
    046     * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
    047     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    048     * @author <a href="mailto:ksh@scand.com">Konstantin Shaposhnikov</a>
    049     * @author Oliver Heger
    050     * @version $Id: BaseConfiguration.java 806862 2009-08-22 15:13:31Z oheger $
    051     */
    052    public class BaseConfiguration extends AbstractConfiguration implements Cloneable
    053    {
    054        /** stores the configuration key-value pairs */
    055        private Map store = new LinkedMap();
    056
    057        /**
    058         * Adds a key/value pair to the map.  This routine does no magic morphing.
    059         * It ensures the keylist is maintained
    060         *
    061         * @param key key to use for mapping
    062         * @param value object to store
    063         */
    064        protected void addPropertyDirect(String key, Object value)
    065        {
    066            Object previousValue = getProperty(key);
    067
    068            if (previousValue == null)
    069            {
    070                store.put(key, value);
    071            }
    072            else if (previousValue instanceof List)
    073            {
    074                // the value is added to the existing list
    075                ((List) previousValue).add(value);
    076            }
    077            else
    078            {
    079                // the previous value is replaced by a list containing the previous value and the new value
    080                List list = new ArrayList();
    081                list.add(previousValue);
    082                list.add(value);
    083
    084                store.put(key, list);
    085            }
    086        }
    087
    088        /**
    089         * Read property from underlying map.
    090         *
    091         * @param key key to use for mapping
    092         *
    093         * @return object associated with the given configuration key.
    094         */
    095        public Object getProperty(String key)
    096        {
    097            return store.get(key);
    098        }
    099
    100        /**
    101         * Check if the configuration is empty
    102         *
    103         * @return <code>true</code> if Configuration is empty,
    104         * <code>false</code> otherwise.
    105         */
    106        public boolean isEmpty()
    107        {
    108            return store.isEmpty();
    109        }
    110
    111        /**
    112         * check if the configuration contains the key
    113         *
    114         * @param key the configuration key
    115         *
    116         * @return <code>true</code> if Configuration contain given key,
    117         * <code>false</code> otherwise.
    118         */
    119        public boolean containsKey(String key)
    120        {
    121            return store.containsKey(key);
    122        }
    123
    124        /**
    125         * Clear a property in the configuration.
    126         *
    127         * @param key the key to remove along with corresponding value.
    128         */
    129        protected void clearPropertyDirect(String key)
    130        {
    131            if (containsKey(key))
    132            {
    133                store.remove(key);
    134            }
    135        }
    136
    137        public void clear()
    138        {
    139            fireEvent(EVENT_CLEAR, null, null, true);
    140            store.clear();
    141            fireEvent(EVENT_CLEAR, null, null, false);
    142        }
    143
    144        /**
    145         * Get the list of the keys contained in the configuration
    146         * repository.
    147         *
    148         * @return An Iterator.
    149         */
    150        public Iterator getKeys()
    151        {
    152            return store.keySet().iterator();
    153        }
    154
    155        /**
    156         * Creates a copy of this object. This implementation will create a deep
    157         * clone, i.e. the map that stores the properties is cloned, too. So changes
    158         * performed at the copy won't affect the original and vice versa.
    159         *
    160         * @return the copy
    161         * @since 1.3
    162         */
    163        public Object clone()
    164        {
    165            try
    166            {
    167                BaseConfiguration copy = (BaseConfiguration) super.clone();
    168                copy.store = (Map) ConfigurationUtils.clone(store);
    169
    170                // Handle collections in the map; they have to be cloned, too
    171                for (Iterator it = store.entrySet().iterator(); it.hasNext();)
    172                {
    173                    Map.Entry e = (Map.Entry) it.next();
    174                    if (e.getValue() instanceof Collection)
    175                    {
    176                        copy.store.put(e.getKey(), new ArrayList((Collection) e
    177                                .getValue()));
    178                    }
    179                }
    180
    181                return copy;
    182            }
    183            catch (CloneNotSupportedException cex)
    184            {
    185                // should not happen
    186                throw new ConfigurationRuntimeException(cex);
    187            }
    188        }
    189    }