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
018package org.apache.commons.configuration2;
019
020import java.util.AbstractMap;
021import java.util.AbstractSet;
022import java.util.Iterator;
023import java.util.Map;
024import java.util.Objects;
025import java.util.Set;
026
027/**
028 * <p>
029 * The {@code ConfigurationMap} wraps a configuration-collection {@link org.apache.commons.configuration2.Configuration}
030 * instance to provide a {@code Map} interface.
031 * </p>
032 *
033 * <p>
034 * <em>Note:</em> This implementation is incomplete.
035 * </p>
036 *
037 * @since 1.0
038 */
039public class ConfigurationMap extends AbstractMap<Object, Object> {
040    /**
041     * The {@code Configuration} wrapped by this class.
042     */
043    private final Configuration configuration;
044
045    /**
046     * Creates a new instance of a {@code ConfigurationMap} that wraps the specified {@code Configuration} instance.
047     *
048     * @param configuration {@code Configuration} instance.
049     */
050    public ConfigurationMap(final Configuration configuration) {
051        this.configuration = Objects.requireNonNull(configuration, "configuration");
052    }
053
054    /**
055     * Gets the wrapped {@code Configuration} object.
056     *
057     * @return the wrapped configuration
058     * @since 1.2
059     */
060    public Configuration getConfiguration() {
061        return configuration;
062    }
063
064    /**
065     * Returns a set with the entries contained in this configuration-based map.
066     *
067     * @return a set with the contained entries
068     * @see java.util.Map#entrySet()
069     */
070    @Override
071    public Set<Map.Entry<Object, Object>> entrySet() {
072        return new ConfigurationSet(configuration);
073    }
074
075    /**
076     * Stores the value for the specified key. The value is stored in the underlying configuration.
077     *
078     * @param key the key (will be converted to a string)
079     * @param value the value
080     * @return the old value of this key or <b>null</b> if it is new
081     * @see java.util.Map#put(Object, Object)
082     */
083    @Override
084    public Object put(final Object key, final Object value) {
085        final String strKey = String.valueOf(key);
086        final Object old = configuration.getProperty(strKey);
087        configuration.setProperty(strKey, value);
088        return old;
089    }
090
091    /**
092     * Gets the value of the specified key. The key is converted to a string and then passed to the underlying
093     * configuration.
094     *
095     * @param key the key
096     * @return the value of this key
097     * @see java.util.Map#get(Object)
098     */
099    @Override
100    public Object get(final Object key) {
101        return configuration.getProperty(String.valueOf(key));
102    }
103
104    /**
105     * Sets of entries in the map.
106     */
107    static class ConfigurationSet extends AbstractSet<Map.Entry<Object, Object>> {
108        /** The configuration mapped to this entry set. */
109        private final Configuration configuration;
110
111        /**
112         * A Map entry in the ConfigurationMap.
113         */
114        private final class Entry implements Map.Entry<Object, Object> {
115            /** The key of the map entry. */
116            private final Object key;
117
118            private Entry(final Object key) {
119                this.key = key;
120            }
121
122            @Override
123            public Object getKey() {
124                return key;
125            }
126
127            @Override
128            public Object getValue() {
129                return configuration.getProperty((String) key);
130            }
131
132            @Override
133            public Object setValue(final Object value) {
134                final Object old = getValue();
135                configuration.setProperty((String) key, value);
136                return old;
137            }
138        }
139
140        /**
141         * Iterator over the entries in the ConfigurationMap.
142         */
143        private final class ConfigurationSetIterator implements Iterator<Map.Entry<Object, Object>> {
144            /** An iterator over the keys in the configuration. */
145            private final Iterator<String> keys;
146
147            private ConfigurationSetIterator() {
148                keys = configuration.getKeys();
149            }
150
151            @Override
152            public boolean hasNext() {
153                return keys.hasNext();
154            }
155
156            @Override
157            public Map.Entry<Object, Object> next() {
158                return new Entry(keys.next());
159            }
160
161            @Override
162            public void remove() {
163                keys.remove();
164            }
165        }
166
167        ConfigurationSet(final Configuration configuration) {
168            this.configuration = configuration;
169        }
170
171        /**
172         * @see java.util.Collection#size()
173         */
174        @Override
175        public int size() {
176            // Ouch. Now _that_ one is expensive...
177            int count = 0;
178            for (final Iterator<String> iterator = configuration.getKeys(); iterator.hasNext();) {
179                iterator.next();
180                count++;
181            }
182            return count;
183        }
184
185        /**
186         * @see java.util.Collection#iterator()
187         */
188        @Override
189        public Iterator<Map.Entry<Object, Object>> iterator() {
190            return new ConfigurationSetIterator();
191        }
192    }
193}