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