~ubuntu-branches/ubuntu/saucy/commons-configuration/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/configuration/MapConfiguration.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-07-01 16:29:44 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130701162944-98waq5gogha5gpn1
Tags: 1.9-1
* New upstream release
* debian/control:
  - Updated Standards-Version to 3.9.4 (no changes)
  - Use canonical URLs for the Vcs-* fields
  - Added new build dependencies (libjavacc-maven-plugin-java, junit4)
  - Upgraded the dependency on the Servlet API (2.5 -> 3.0)
  - Removed the dependency on the Activation Framework (glassfish-activation)
  - Replaced the dependency on glassfish-mail with libgnumail-java
  - Removed the unused dependencies:
    liblog4j1.2-java-doc, libmaven-assembly-plugin-java
  - Replaced the dependency on libcommons-jexl-java by libcommons-jexl2-java
* debian/watch: Changed to point the official Apache distribution server
* Removed the obsolete file debian/ant.properties
* Installed the upstream changelog in the binary packages
* Added the report plugins to maven.ignoreRules
* Added the classpath attribute to the jar manifest

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *     http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 * See the License for the specific language governing permissions and
 
15
 * limitations under the License.
 
16
 */
 
17
 
 
18
package org.apache.commons.configuration;
 
19
 
 
20
import java.util.ArrayList;
 
21
import java.util.HashMap;
 
22
import java.util.Iterator;
 
23
import java.util.List;
 
24
import java.util.Map;
 
25
import java.util.Properties;
 
26
 
 
27
/**
 
28
 * <p>
 
29
 * A Map based Configuration.
 
30
 * </p>
 
31
 * <p>
 
32
 * This implementation of the {@code Configuration} interface is
 
33
 * initialized with a {@code java.util.Map}. The methods of the
 
34
 * {@code Configuration} interface are implemented on top of the content of
 
35
 * this map. The following storage scheme is used:
 
36
 * </p>
 
37
 * <p>
 
38
 * Property keys are directly mapped to map keys, i.e. the
 
39
 * {@code getProperty()} method directly performs a {@code get()} on
 
40
 * the map. Analogously, {@code setProperty()} or
 
41
 * {@code addProperty()} operations write new data into the map. If a value
 
42
 * is added to an existing property, a {@code java.util.List} is created,
 
43
 * which stores the values of this property.
 
44
 * </p>
 
45
 * <p>
 
46
 * An important use case of this class is to treat a map as a
 
47
 * {@code Configuration} allowing access to its data through the richer
 
48
 * interface. This can be a bit problematic in some cases because the map may
 
49
 * contain values that need not adhere to the default storage scheme used by
 
50
 * typical configuration implementations, e.g. regarding lists. In such cases
 
51
 * care must be taken when manipulating the data through the
 
52
 * {@code Configuration} interface, e.g. by calling
 
53
 * {@code addProperty()}; results may be different than expected.
 
54
 * </p>
 
55
 * <p>
 
56
 * An important point is the handling of list delimiters: If delimiter parsing
 
57
 * is enabled (which it is per default), {@code getProperty()} checks
 
58
 * whether the value of a property is a string and whether it contains the list
 
59
 * delimiter character. If this is the case, the value is split at the delimiter
 
60
 * resulting in a list. This split operation typically also involves trimming
 
61
 * the single values as the list delimiter character may be surrounded by
 
62
 * whitespace. Trimming can be disabled with the
 
63
 * {@link #setTrimmingDisabled(boolean)} method. The whole list splitting
 
64
 * behavior can be disabled using the
 
65
 * {@link #setDelimiterParsingDisabled(boolean)} method.
 
66
 * </p>
 
67
 * <p>
 
68
 * Notice that list splitting is only performed for single string values. If a
 
69
 * property has multiple values, the single values are not split even if they
 
70
 * contain the list delimiter character.
 
71
 * </p>
 
72
 * <p>
 
73
 * As the underlying {@code Map} is directly used as store of the property
 
74
 * values, the thread-safety of this {@code Configuration} implementation
 
75
 * depends on the map passed to the constructor.
 
76
 * </p>
 
77
 * <p>
 
78
 * Notes about type safety: For properties with multiple values this implementation
 
79
 * creates lists of type {@code Object} and stores them. If a property is assigned
 
80
 * another value, the value is added to the list. This can cause problems if the
 
81
 * map passed to the constructor already contains lists of other types. This
 
82
 * should be avoided, otherwise it cannot be guaranteed that the application
 
83
 * might throw {@code ClassCastException} exceptions later.
 
84
 * </p>
 
85
 *
 
86
 * @author Emmanuel Bourg
 
87
 * @version $Id: MapConfiguration.java 1210171 2011-12-04 18:32:07Z oheger $
 
88
 * @since 1.1
 
89
 */
 
90
public class MapConfiguration extends AbstractConfiguration implements Cloneable
 
91
{
 
92
    /** The Map decorated by this configuration. */
 
93
    protected Map<String, Object> map;
 
94
 
 
95
    /** A flag whether trimming of property values should be disabled.*/
 
96
    private boolean trimmingDisabled;
 
97
 
 
98
    /**
 
99
     * Create a Configuration decorator around the specified Map. The map is
 
100
     * used to store the configuration properties, any change will also affect
 
101
     * the Map.
 
102
     *
 
103
     * @param map the map
 
104
     */
 
105
    public MapConfiguration(Map<String, Object> map)
 
106
    {
 
107
        this.map = map;
 
108
    }
 
109
 
 
110
    /**
 
111
     * Creates a new instance of {@code MapConfiguration} and initializes its
 
112
     * content from the specified {@code Properties} object. The resulting
 
113
     * configuration is not connected to the {@code Properties} object, but all
 
114
     * keys which are strings are copied (keys of other types are ignored).
 
115
     *
 
116
     * @param props the {@code Properties} object defining the content of this
 
117
     *        configuration
 
118
     * @throws NullPointerException if the {@code Properties} object is
 
119
     *         <b>null</b>
 
120
     * @since 1.8
 
121
     */
 
122
    public MapConfiguration(Properties props)
 
123
    {
 
124
        map = convertPropertiesToMap(props);
 
125
    }
 
126
 
 
127
    /**
 
128
     * Return the Map decorated by this configuration.
 
129
     *
 
130
     * @return the map this configuration is based onto
 
131
     */
 
132
    public Map<String, Object> getMap()
 
133
    {
 
134
        return map;
 
135
    }
 
136
 
 
137
    /**
 
138
     * Returns the flag whether trimming of property values is disabled.
 
139
     *
 
140
     * @return <b>true</b> if trimming of property values is disabled;
 
141
     *         <b>false</b> otherwise
 
142
     * @since 1.7
 
143
     */
 
144
    public boolean isTrimmingDisabled()
 
145
    {
 
146
        return trimmingDisabled;
 
147
    }
 
148
 
 
149
    /**
 
150
     * Sets a flag whether trimming of property values is disabled. This flag is
 
151
     * only evaluated if list splitting is enabled. Refer to the header comment
 
152
     * for more information about list splitting and trimming.
 
153
     *
 
154
     * @param trimmingDisabled a flag whether trimming of property values should
 
155
     *        be disabled
 
156
     * @since 1.7
 
157
     */
 
158
    public void setTrimmingDisabled(boolean trimmingDisabled)
 
159
    {
 
160
        this.trimmingDisabled = trimmingDisabled;
 
161
    }
 
162
 
 
163
    public Object getProperty(String key)
 
164
    {
 
165
        Object value = map.get(key);
 
166
        if ((value instanceof String) && (!isDelimiterParsingDisabled()))
 
167
        {
 
168
            List<String> list = PropertyConverter.split((String) value, getListDelimiter(), !isTrimmingDisabled());
 
169
            return list.size() > 1 ? list : list.get(0);
 
170
        }
 
171
        else
 
172
        {
 
173
            return value;
 
174
        }
 
175
    }
 
176
 
 
177
    @Override
 
178
    protected void addPropertyDirect(String key, Object value)
 
179
    {
 
180
        Object previousValue = getProperty(key);
 
181
 
 
182
        if (previousValue == null)
 
183
        {
 
184
            map.put(key, value);
 
185
        }
 
186
        else if (previousValue instanceof List)
 
187
        {
 
188
            // the value is added to the existing list
 
189
            // Note: This is problematic. See header comment!
 
190
            ((List<Object>) previousValue).add(value);
 
191
        }
 
192
        else
 
193
        {
 
194
            // the previous value is replaced by a list containing the previous value and the new value
 
195
            List<Object> list = new ArrayList<Object>();
 
196
            list.add(previousValue);
 
197
            list.add(value);
 
198
 
 
199
            map.put(key, list);
 
200
        }
 
201
    }
 
202
 
 
203
    public boolean isEmpty()
 
204
    {
 
205
        return map.isEmpty();
 
206
    }
 
207
 
 
208
    public boolean containsKey(String key)
 
209
    {
 
210
        return map.containsKey(key);
 
211
    }
 
212
 
 
213
    @Override
 
214
    protected void clearPropertyDirect(String key)
 
215
    {
 
216
        map.remove(key);
 
217
    }
 
218
 
 
219
    public Iterator<String> getKeys()
 
220
    {
 
221
        return map.keySet().iterator();
 
222
    }
 
223
 
 
224
    /**
 
225
     * Returns a copy of this object. The returned configuration will contain
 
226
     * the same properties as the original. Event listeners are not cloned.
 
227
     *
 
228
     * @return the copy
 
229
     * @since 1.3
 
230
     */
 
231
    @Override
 
232
    public Object clone()
 
233
    {
 
234
        try
 
235
        {
 
236
            MapConfiguration copy = (MapConfiguration) super.clone();
 
237
            copy.clearConfigurationListeners();
 
238
            // Safe because ConfigurationUtils returns a map of the same types.
 
239
            @SuppressWarnings("unchecked")
 
240
            Map<String, Object> clonedMap = (Map<String, Object>) ConfigurationUtils.clone(map);
 
241
            copy.map = clonedMap;
 
242
            return copy;
 
243
        }
 
244
        catch (CloneNotSupportedException cex)
 
245
        {
 
246
            // cannot happen
 
247
            throw new ConfigurationRuntimeException(cex);
 
248
        }
 
249
    }
 
250
 
 
251
    /**
 
252
     * Helper method for copying all string keys from the given
 
253
     * {@code Properties} object to a newly created map.
 
254
     *
 
255
     * @param props the {@code Properties} to be copied
 
256
     * @return a newly created map with all string keys of the properties
 
257
     */
 
258
    private static Map<String, Object> convertPropertiesToMap(Properties props)
 
259
    {
 
260
        Map<String, Object> map = new HashMap<String, Object>();
 
261
        for (Map.Entry<Object, Object> e : props.entrySet())
 
262
        {
 
263
            if (e.getKey() instanceof String)
 
264
            {
 
265
                map.put((String) e.getKey(), e.getValue());
 
266
            }
 
267
        }
 
268
        return map;
 
269
    }
 
270
}