##### Coverage Report - org.apache.commons.configuration.AbstractConfiguration

Classes in this File | Line Coverage | Branch Coverage | Complexity
AbstractConfiguration |
94% | 223/236
97% | 63/65
| 2.9482758620689653;2,948
AbstractConfiguration$1 |
100% | 3/3
100% | 1/1
| 2.9482758620689653;2,948

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.math.BigDecimal;
21 |  |
     import java.math.BigInteger;
22 |  |
     import java.util.ArrayList;
23 |  |
     import java.util.Iterator;
24 |  |
     import java.util.List;
25 |  |
     import java.util.NoSuchElementException;
26 |  |
     import java.util.Properties;
27 |  |
28 |  |
     import org.apache.commons.collections.Predicate;
29 |  |
     import org.apache.commons.collections.iterators.FilterIterator;
30 |  |
     import org.apache.commons.configuration.event.EventSource;
31 |  |
     import org.apache.commons.lang.BooleanUtils;
32 |  |
33 |  |
     /**
34 |  |
      * <p>Abstract configuration class. Provides basic functionality but does not
35 |  |
      * store any data.</p>
36 |  |
      * <p>If you want to write your own Configuration class then you should
37 |  |
      * implement only abstract methods from this class. A lot of functionality
38 |  |
      * needed by typical implementations of the <code>Configuration</conde>
39 |  |
      * interface is already provided by this base class. Following is a list of
40 |  |
      * feauters implemented here:
41 |  |
      * <ul><li>Data conversion support. The various data types required by the
42 |  |
      * <code>Configuration</code> interface are already handled by this base class.
43 |  |
      * A concrete sub class only needs to provide a generic <code>getProperty()</code>
44 |  |
      * method.</li>
45 |  |
      * <li>Support for variable interpolation. Property values containing special
46 |  |
      * variable tokens (like <code>${var}</code>) will be replaced by their
47 |  |
      * corresponding values.</li>
48 |  |
      * <li>Support for string lists. The values of properties to be added to this
49 |  |
      * configuration are checked whether they contain a list delimiter character. If
50 |  |
      * this is the case and if list splitting is enabled, the string is splitted and
51 |  |
      * multiple values are added for this property.</li>
52 |  |
      * <li>Basic event support. Whenever this configuration is modified registered
53 |  |
      * event listeners are notified. Refer to the various <code>EVENT_XXX</code>
54 |  |
      * constants to get an impression about which event types are supported.</li>
55 |  |
      * </ul></p>
56 |  |
      *
57 |  |
      * @author <a href="mailto:ksh@scand.com">Konstantin Shaposhnikov </a>
58 |  |
      * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger </a>
59 |  |
      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen </a>
60 |  |
      * @version $Id: AbstractConfiguration.java,v 1.29 2004/12/02 22:05:52 ebourg
61 |  |
      * Exp $
62 |  |
      */
63 | 4494 |
     public abstract class AbstractConfiguration extends EventSource implements Configuration
64 |  |
     {
65 |  |
         /** Constant for the add property event type.*/
66 |  |
         public static final int EVENT_ADD_PROPERTY = 1;
67 |  |
68 |  |
         /** Constant for the clear property event type.*/
69 |  |
         public static final int EVENT_CLEAR_PROPERTY = 2;
70 |  |
71 |  |
         /** Constant for the set property event type.*/
72 |  |
         public static final int EVENT_SET_PROPERTY = 3;
73 |  |
74 |  |
         /** Constant for the clear configuration event type.*/
75 |  |
         public static final int EVENT_CLEAR = 4;
76 |  |
77 |  |
         /** start token */
78 |  |
         protected static final String START_TOKEN = "${";
79 |  |
80 |  |
         /** end token */
81 |  |
         protected static final String END_TOKEN = "}";
82 |  |
83 |  |
         /** The default value for listDelimiter */
84 | 54 |
         private static char defaultListDelimiter = ',';
85 |  |
86 |  |
         /** Delimiter used to convert single values to lists */
87 | 2247 |
         private char listDelimiter = defaultListDelimiter;
88 |  |
89 |  |
         /**
90 |  |
          * When set to true the given configuration delimiter will not be used
91 |  |
          * while parsing for this configuration.
92 |  |
          */
93 |  |
         private boolean delimiterParsingDisabled;
94 |  |
95 |  |
         /**
96 |  |
          * Whether the configuration should throw NoSuchElementExceptions or simply
97 |  |
          * return null when a property does not exist. Defaults to return null.
98 |  |
          */
99 |  |
         private boolean throwExceptionOnMissing;
100 |  |
101 |  |
         /**
102 |  |
          * For configurations extending AbstractConfiguration, allow them to change
103 |  |
          * the listDelimiter from the default comma (","). This value will be used
104 |  |
          * only when creating new configurations. Those already created will not be
105 |  |
          * affected by this change
106 |  |
          *
107 |  |
          * @param delimiter The new listDelimiter
108 |  |
          */
109 |  |
         public static void setDefaultListDelimiter(char delimiter)
110 |  |
         {
111 | 2 |
             AbstractConfiguration.defaultListDelimiter = delimiter;
112 | 2 |
         }
113 |  |
114 |  |
         /**
115 |  |
          * Sets the default list delimiter.
116 |  |
          *
117 |  |
          * @param delimiter the delimiter character
118 |  |
          * @deprecated Use AbstractConfiguration.setDefaultListDelimiter(char)
119 |  |
          * instead
120 |  |
          */
121 |  |
         public static void setDelimiter(char delimiter)
122 |  |
         {
123 | 0 |
             setDefaultListDelimiter(delimiter);
124 | 0 |
         }
125 |  |
126 |  |
         /**
127 |  |
          * Retrieve the current delimiter. By default this is a comma (",").
128 |  |
          *
129 |  |
          * @return The delimiter in use
130 |  |
          */
131 |  |
         public static char getDefaultListDelimiter()
132 |  |
         {
133 | 50 |
             return AbstractConfiguration.defaultListDelimiter;
134 |  |
         }
135 |  |
136 |  |
         /**
137 |  |
          * Returns the default list delimiter.
138 |  |
          *
139 |  |
          * @return the default list delimiter
140 |  |
          * @deprecated Use AbstractConfiguration.getDefaultListDelimiter() instead
141 |  |
          */
142 |  |
         public static char getDelimiter()
143 |  |
         {
144 | 0 |
             return getDefaultListDelimiter();
145 |  |
         }
146 |  |
147 |  |
         /**
148 |  |
          * Change the list delimiter for this configuration.
149 |  |
          *
150 |  |
          * Note: this change will only be effective for new parsings. If you
151 |  |
          * want it to take effect for all loaded properties use the no arg constructor
152 |  |
          * and call this method before setting the source.
153 |  |
          *
154 |  |
          * @param listDelimiter The new listDelimiter
155 |  |
          */
156 |  |
         public void setListDelimiter(char listDelimiter)
157 |  |
         {
158 | 194 |
             this.listDelimiter = listDelimiter;
159 | 194 |
         }
160 |  |
161 |  |
         /**
162 |  |
          * Retrieve the delimiter for this configuration. The default
163 |  |
          * is the value of defaultListDelimiter.
164 |  |
          *
165 |  |
          * @return The listDelimiter in use
166 |  |
          */
167 |  |
         public char getListDelimiter()
168 |  |
         {
169 | 46862 |
             return listDelimiter;
170 |  |
         }
171 |  |
172 |  |
         /**
173 |  |
          * Determine if this configuration is using delimiters when parsing
174 |  |
          * property values to convert them to lists of values. Defaults to false
175 |  |
          * @return true if delimiters are not being used
176 |  |
          */
177 |  |
         public boolean isDelimiterParsingDisabled()
178 |  |
         {
179 | 45973 |
             return delimiterParsingDisabled;
180 |  |
         }
181 |  |
182 |  |
         /**
183 |  |
          * Set whether this configuration should use delimiters when parsing
184 |  |
          * property values to convert them to lists of values. By default delimiter
185 |  |
          * parsing is enabled
186 |  |
          *
187 |  |
          * Note: this change will only be effective for new parsings. If you
188 |  |
          * want it to take effect for all loaded properties use the no arg constructor
189 |  |
          * and call this method before setting source.
190 |  |
          * @param delimiterParsingDisabled a flag whether delimiter parsing should
191 |  |
          * be disabled
192 |  |
          */
193 |  |
         public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled)
194 |  |
         {
195 | 197 |
             this.delimiterParsingDisabled = delimiterParsingDisabled;
196 | 197 |
         }
197 |  |
198 |  |
         /**
199 |  |
          * Allows to set the <code>throwExceptionOnMissing</code> flag. This
200 |  |
          * flag controls the behavior of property getter methods that return
201 |  |
          * objects if the requested property is missing. If the flag is set to
202 |  |
          * <b>false</b> (which is the default value), these methods will return
203 |  |
          * <b>null</b>. If set to <b>true</b>, they will throw a
204 |  |
          * <code>NoSuchElementException</code> exception. Note that getter methods
205 |  |
          * for primitive data types are not affected by this flag.
206 |  |
          *
207 |  |
          * @param throwExceptionOnMissing The new value for the property
208 |  |
          */
209 |  |
         public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
210 |  |
         {
211 | 683 |
             this.throwExceptionOnMissing = throwExceptionOnMissing;
212 | 683 |
         }
213 |  |
214 |  |
         /**
215 |  |
          * Returns true if missing values throw Exceptions.
216 |  |
          *
217 |  |
          * @return true if missing values throw Exceptions
218 |  |
          */
219 |  |
         public boolean isThrowExceptionOnMissing()
220 |  |
         {
221 | 662 |
             return throwExceptionOnMissing;
222 |  |
         }
223 |  |
224 |  |
         /**
225 |  |
          * {@inheritDoc}
226 |  |
          */
227 |  |
         public void addProperty(String key, Object value)
228 |  |
         {
229 | 36265 |
             fireEvent(EVENT_ADD_PROPERTY, key, value, true);
230 |  |
231 | 36265 |
             if (!isDelimiterParsingDisabled())
232 |  |
             {
233 | 36213 |
                 Iterator it = PropertyConverter.toIterator(value, getListDelimiter());
234 | 112164 |
                 while (it.hasNext())
235 |  |
                 {
236 | 39739 |
                     addPropertyDirect(key, it.next());
237 |  |
                 }
238 |  |
             }
239 |  |
             else
240 |  |
             {
241 | 52 |
                 addPropertyDirect(key, value);
242 |  |
             }
243 |  |
244 | 36264 |
             fireEvent(EVENT_ADD_PROPERTY, key, value, false);
245 | 36264 |
         }
246 |  |
247 |  |
         /**
248 |  |
          * Adds a key/value pair to the Configuration. Override this method to
249 |  |
          * provide write acces to underlying Configuration store.
250 |  |
          *
251 |  |
          * @param key key to use for mapping
252 |  |
          * @param value object to store
253 |  |
          */
254 |  |
         protected abstract void addPropertyDirect(String key, Object value);
255 |  |
256 |  |
         /**
257 |  |
          * interpolate key names to handle ${key} stuff
258 |  |
          *
259 |  |
          * @param base string to interpolate
260 |  |
          *
261 |  |
          * @return returns the key name with the ${key} substituted
262 |  |
          */
263 |  |
         protected String interpolate(String base)
264 |  |
         {
265 | 682 |
             Object result = interpolate((Object) base);
266 | 680 |
             return (result == null) ? null : result.toString();
267 |  |
         }
268 |  |
269 |  |
         /**
270 |  |
          * Returns the interpolated value. Non String values are returned without change.
271 |  |
          *
272 |  |
          * @param value the value to interpolate
273 |  |
          *
274 |  |
          * @return returns the value with variables substituted
275 |  |
          */
276 |  |
         protected Object interpolate(Object value)
277 |  |
         {
278 | 2093 |
             return PropertyConverter.interpolate(value, this);
279 |  |
         }
280 |  |
281 |  |
         /**
282 |  |
          * Recursive handler for multple levels of interpolation.
283 |  |
          *
284 |  |
          * When called the first time, priorVariables should be null.
285 |  |
          *
286 |  |
          * @param base string with the ${key} variables
287 |  |
          * @param priorVariables serves two purposes: to allow checking for loops,
288 |  |
          * and creating a meaningful exception message should a loop occur. It's
289 |  |
          * 0'th element will be set to the value of base from the first call. All
290 |  |
          * subsequent interpolated variables are added afterward.
291 |  |
          *
292 |  |
          * @return the string with the interpolation taken care of
293 |  |
          * @deprecated Interpolation is now handled by
294 |  |
          * <code>{@link PropertyConverter}</code>; this method will no longer be
295 |  |
          * called
296 |  |
          */
297 |  |
         protected String interpolateHelper(String base, List priorVariables)
298 |  |
         {
299 | 0 |
             return base; // just a dummy implementation
300 |  |
         }
301 |  |
302 |  |
         /**
303 |  |
          * {@inheritDoc}
304 |  |
          */
305 |  |
         public Configuration subset(String prefix)
306 |  |
         {
307 | 40 |
             return new SubsetConfiguration(this, prefix, ".");
308 |  |
         }
309 |  |
310 |  |
         /**
311 |  |
          * {@inheritDoc}
312 |  |
          */
313 |  |
         public abstract boolean isEmpty();
314 |  |
315 |  |
         /**
316 |  |
          * {@inheritDoc}
317 |  |
          */
318 |  |
         public abstract boolean containsKey(String key);
319 |  |
320 |  |
         /**
321 |  |
          * {@inheritDoc}
322 |  |
          */
323 |  |
         public void setProperty(String key, Object value)
324 |  |
         {
325 | 781 |
             fireEvent(EVENT_SET_PROPERTY, key, value, true);
326 | 781 |
             setDetailEvents(false);
327 |  |
             try
328 |  |
             {
329 | 781 |
                 clearProperty(key);
330 | 781 |
                 addProperty(key, value);
331 | 781 |
             }
332 |  |
             finally
333 |  |
             {
334 | 0 |
                 setDetailEvents(true);
335 |  |
             }
336 | 781 |
             fireEvent(EVENT_SET_PROPERTY, key, value, false);
337 | 781 |
         }
338 |  |
339 |  |
         /**
340 |  |
          * Removes the specified property from this configuration. This
341 |  |
          * implementation performs some preparations and then delegates to
342 |  |
          * <code>clearPropertyDirect()</code>, which will do the real work.
343 |  |
          *
344 |  |
          * @param key the key to be removed
345 |  |
          */
346 |  |
         public void clearProperty(String key)
347 |  |
         {
348 | 816 |
             fireEvent(EVENT_CLEAR_PROPERTY, key, null, true);
349 | 816 |
             clearPropertyDirect(key);
350 | 816 |
             fireEvent(EVENT_CLEAR_PROPERTY, key, null, false);
351 | 816 |
         }
352 |  |
353 |  |
         /**
354 |  |
          * Removes the specified property from this configuration. This method is
355 |  |
          * called by <code>clearProperty()</code> after it has done some
356 |  |
          * preparations. It should be overriden in sub classes. This base
357 |  |
          * implementation is just left empty.
358 |  |
          *
359 |  |
          * @param key the key to be removed
360 |  |
          */
361 |  |
         protected void clearPropertyDirect(String key)
362 |  |
         {
363 |  |
             // override in sub classes
364 | 0 |
         }
365 |  |
366 |  |
         /**
367 |  |
          * {@inheritDoc}
368 |  |
          */
369 |  |
         public void clear()
370 |  |
         {
371 | 15 |
             fireEvent(EVENT_CLEAR, null, null, true);
372 | 15 |
             setDetailEvents(false);
373 |  |
             try
374 |  |
             {
375 | 15 |
                 Iterator it = getKeys();
376 | 213 |
                 while (it.hasNext())
377 |  |
                 {
378 | 183 |
                     String key = (String) it.next();
379 | 183 |
                     it.remove();
380 |  |
381 | 183 |
                     if (containsKey(key))
382 |  |
                     {
383 |  |
                         // workaround for Iterators that do not remove the property on calling remove()
384 | 180 |
                         clearProperty(key);
385 |  |
                     }
386 |  |
                 }
387 | 15 |
             }
388 |  |
             finally
389 |  |
             {
390 | 0 |
                 setDetailEvents(true);
391 |  |
             }
392 | 15 |
             fireEvent(EVENT_CLEAR, null, null, false);
393 | 15 |
         }
394 |  |
395 |  |
         /**
396 |  |
          * {@inheritDoc}
397 |  |
          */
398 |  |
         public abstract Iterator getKeys();
399 |  |
400 |  |
         /**
401 |  |
          * {@inheritDoc}
402 |  |
          */
403 |  |
         public Iterator getKeys(final String prefix)
404 |  |
         {
405 | 37 |
             return new FilterIterator(getKeys(), new Predicate()
406 |  |
             {
407 | 37 |
                 public boolean evaluate(Object obj)
408 |  |
                 {
409 | 426 |
                     String key = (String) obj;
410 | 426 |
                     return key.startsWith(prefix + ".") || key.equals(prefix);
411 |  |
                 }
412 |  |
             });
413 |  |
         }
414 |  |
415 |  |
         /**
416 |  |
          * {@inheritDoc}
417 |  |
          */
418 |  |
         public Properties getProperties(String key)
419 |  |
         {
420 | 4 |
             return getProperties(key, null);
421 |  |
         }
422 |  |
423 |  |
         /**
424 |  |
          * Get a list of properties associated with the given configuration key.
425 |  |
          *
426 |  |
          * @param key The configuration key.
427 |  |
          * @param defaults Any default values for the returned
428 |  |
          * <code>Properties</code> object. Ignored if <code>null</code>.
429 |  |
          *
430 |  |
          * @return The associated properties if key is found.
431 |  |
          *
432 |  |
          * @throws ConversionException is thrown if the key maps to an object that
433 |  |
          * is not a String/List of Strings.
434 |  |
          *
435 |  |
          * @throws IllegalArgumentException if one of the tokens is malformed (does
436 |  |
          * not contain an equals sign).
437 |  |
          */
438 |  |
         public Properties getProperties(String key, Properties defaults)
439 |  |
         {
440 |  |
             /*
441 |  |
              * Grab an array of the tokens for this key.
442 |  |
              */
443 | 4 |
             String[] tokens = getStringArray(key);
444 |  |
445 |  |
             /*
446 |  |
              * Each token is of the form 'key=value'.
447 |  |
              */
448 | 4 |
             Properties props = defaults == null ? new Properties() : new Properties(defaults);
449 | 10 |
             for (int i = 0; i < tokens.length; i++)
450 |  |
             {
451 | 8 |
                 String token = tokens[i];
452 | 8 |
                 int equalSign = token.indexOf('=');
453 | 8 |
                 if (equalSign > 0)
454 |  |
                 {
455 | 6 |
                     String pkey = token.substring(0, equalSign).trim();
456 | 6 |
                     String pvalue = token.substring(equalSign + 1).trim();
457 | 6 |
                     props.put(pkey, pvalue);
458 |  |
                 }
459 | 2 |
                 else if (tokens.length == 1 && "".equals(token))
460 |  |
                 {
461 |  |
                     // Semantically equivalent to an empty Properties
462 |  |
                     // object.
463 | 2 |
                     break;
464 |  |
                 }
465 |  |
                 else
466 |  |
                 {
467 | 0 |
                     throw new IllegalArgumentException('\'' + token + "' does not contain an equals sign");
468 |  |
                 }
469 |  |
             }
470 | 4 |
             return props;
471 |  |
         }
472 |  |
473 |  |
         /**
474 |  |
          * {@inheritDoc}
475 |  |
          * @see PropertyConverter#toBoolean(Object)
476 |  |
          */
477 |  |
         public boolean getBoolean(String key)
478 |  |
         {
479 | 58 |
             Boolean b = getBoolean(key, null);
480 | 56 |
             if (b != null)
481 |  |
             {
482 | 54 |
                 return b.booleanValue();
483 |  |
             }
484 |  |
             else
485 |  |
             {
486 | 2 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
487 |  |
             }
488 |  |
         }
489 |  |
490 |  |
         /**
491 |  |
          * {@inheritDoc}
492 |  |
          * @see PropertyConverter#toBoolean(Object)
493 |  |
          */
494 |  |
         public boolean getBoolean(String key, boolean defaultValue)
495 |  |
         {
496 | 11 |
             return getBoolean(key, BooleanUtils.toBooleanObject(defaultValue)).booleanValue();
497 |  |
         }
498 |  |
499 |  |
         /**
500 |  |
          * Obtains the value of the specified key and tries to convert it into a
501 |  |
          * <code>Boolean</code> object. If the property has no value, the passed
502 |  |
          * in default value will be used.
503 |  |
          *
504 |  |
          * @param key the key of the property
505 |  |
          * @param defaultValue the default value
506 |  |
          * @return the value of this key converted to a <code>Boolean</code>
507 |  |
          * @throws ConversionException if the value cannot be converted to a
508 |  |
          * <code>Boolean</code>
509 |  |
          * @see PropertyConverter#toBoolean(Object)
510 |  |
          */
511 |  |
         public Boolean getBoolean(String key, Boolean defaultValue)
512 |  |
         {
513 | 100 |
             Object value = resolveContainerStore(key);
514 |  |
515 | 100 |
             if (value == null)
516 |  |
             {
517 | 27 |
                 return defaultValue;
518 |  |
             }
519 |  |
             else
520 |  |
             {
521 |  |
                 try
522 |  |
                 {
523 | 73 |
                     return PropertyConverter.toBoolean(interpolate(value));
524 |  |
                 }
525 |  |
                 catch (ConversionException e)
526 |  |
                 {
527 | 3 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Boolean object", e);
528 |  |
                 }
529 |  |
             }
530 |  |
         }
531 |  |
532 |  |
         /**
533 |  |
          * {@inheritDoc}
534 |  |
          */
535 |  |
         public byte getByte(String key)
536 |  |
         {
537 | 15 |
             Byte b = getByte(key, null);
538 | 13 |
             if (b != null)
539 |  |
             {
540 | 11 |
                 return b.byteValue();
541 |  |
             }
542 |  |
             else
543 |  |
             {
544 | 2 |
                 throw new NoSuchElementException('\'' + key + " doesn't map to an existing object");
545 |  |
             }
546 |  |
         }
547 |  |
548 |  |
         /**
549 |  |
          * {@inheritDoc}
550 |  |
          */
551 |  |
         public byte getByte(String key, byte defaultValue)
552 |  |
         {
553 | 4 |
             return getByte(key, new Byte(defaultValue)).byteValue();
554 |  |
         }
555 |  |
556 |  |
         /**
557 |  |
          * {@inheritDoc}
558 |  |
          */
559 |  |
         public Byte getByte(String key, Byte defaultValue)
560 |  |
         {
561 | 22 |
             Object value = resolveContainerStore(key);
562 |  |
563 | 22 |
             if (value == null)
564 |  |
             {
565 | 4 |
                 return defaultValue;
566 |  |
             }
567 |  |
             else
568 |  |
             {
569 |  |
                 try
570 |  |
                 {
571 | 18 |
                     return PropertyConverter.toByte(interpolate(value));
572 |  |
                 }
573 |  |
                 catch (ConversionException e)
574 |  |
                 {
575 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Byte object", e);
576 |  |
                 }
577 |  |
             }
578 |  |
         }
579 |  |
580 |  |
         /**
581 |  |
          * {@inheritDoc}
582 |  |
          */
583 |  |
         public double getDouble(String key)
584 |  |
         {
585 | 15 |
             Double d = getDouble(key, null);
586 | 13 |
             if (d != null)
587 |  |
             {
588 | 11 |
                 return d.doubleValue();
589 |  |
             }
590 |  |
             else
591 |  |
             {
592 | 2 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
593 |  |
             }
594 |  |
         }
595 |  |
596 |  |
         /**
597 |  |
          * {@inheritDoc}
598 |  |
          */
599 |  |
         public double getDouble(String key, double defaultValue)
600 |  |
         {
601 | 11 |
             return getDouble(key, new Double(defaultValue)).doubleValue();
602 |  |
         }
603 |  |
604 |  |
         /**
605 |  |
          * {@inheritDoc}
606 |  |
          */
607 |  |
         public Double getDouble(String key, Double defaultValue)
608 |  |
         {
609 | 29 |
             Object value = resolveContainerStore(key);
610 |  |
611 | 29 |
             if (value == null)
612 |  |
             {
613 | 11 |
                 return defaultValue;
614 |  |
             }
615 |  |
             else
616 |  |
             {
617 |  |
                 try
618 |  |
                 {
619 | 18 |
                     return PropertyConverter.toDouble(interpolate(value));
620 |  |
                 }
621 |  |
                 catch (ConversionException e)
622 |  |
                 {
623 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Double object", e);
624 |  |
                 }
625 |  |
             }
626 |  |
         }
627 |  |
628 |  |
         /**
629 |  |
          * {@inheritDoc}
630 |  |
          */
631 |  |
         public float getFloat(String key)
632 |  |
         {
633 | 14 |
             Float f = getFloat(key, null);
634 | 12 |
             if (f != null)
635 |  |
             {
636 | 10 |
                 return f.floatValue();
637 |  |
             }
638 |  |
             else
639 |  |
             {
640 | 2 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
641 |  |
             }
642 |  |
         }
643 |  |
644 |  |
         /**
645 |  |
          * {@inheritDoc}
646 |  |
          */
647 |  |
         public float getFloat(String key, float defaultValue)
648 |  |
         {
649 | 7 |
             return getFloat(key, new Float(defaultValue)).floatValue();
650 |  |
         }
651 |  |
652 |  |
         /**
653 |  |
          * {@inheritDoc}
654 |  |
          */
655 |  |
         public Float getFloat(String key, Float defaultValue)
656 |  |
         {
657 | 24 |
             Object value = resolveContainerStore(key);
658 |  |
659 | 24 |
             if (value == null)
660 |  |
             {
661 | 7 |
                 return defaultValue;
662 |  |
             }
663 |  |
             else
664 |  |
             {
665 |  |
                 try
666 |  |
                 {
667 | 17 |
                     return PropertyConverter.toFloat(interpolate(value));
668 |  |
                 }
669 |  |
                 catch (ConversionException e)
670 |  |
                 {
671 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Float object", e);
672 |  |
                 }
673 |  |
             }
674 |  |
         }
675 |  |
676 |  |
         /**
677 |  |
          * {@inheritDoc}
678 |  |
          */
679 |  |
         public int getInt(String key)
680 |  |
         {
681 | 39 |
             Integer i = getInteger(key, null);
682 | 39 |
             if (i != null)
683 |  |
             {
684 | 39 |
                 return i.intValue();
685 |  |
             }
686 |  |
             else
687 |  |
             {
688 | 0 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
689 |  |
             }
690 |  |
         }
691 |  |
692 |  |
         /**
693 |  |
          * {@inheritDoc}
694 |  |
          */
695 |  |
         public int getInt(String key, int defaultValue)
696 |  |
         {
697 | 3 |
             Integer i = getInteger(key, null);
698 |  |
699 | 3 |
             if (i == null)
700 |  |
             {
701 | 3 |
                 return defaultValue;
702 |  |
             }
703 |  |
704 | 0 |
             return i.intValue();
705 |  |
         }
706 |  |
707 |  |
         /**
708 |  |
          * {@inheritDoc}
709 |  |
          */
710 |  |
         public Integer getInteger(String key, Integer defaultValue)
711 |  |
         {
712 | 43 |
             Object value = resolveContainerStore(key);
713 |  |
714 | 43 |
             if (value == null)
715 |  |
             {
716 | 3 |
                 return defaultValue;
717 |  |
             }
718 |  |
             else
719 |  |
             {
720 |  |
                 try
721 |  |
                 {
722 | 40 |
                     return PropertyConverter.toInteger(interpolate(value));
723 |  |
                 }
724 |  |
                 catch (ConversionException e)
725 |  |
                 {
726 | 0 |
                     throw new ConversionException('\'' + key + "' doesn't map to an Integer object", e);
727 |  |
                 }
728 |  |
             }
729 |  |
         }
730 |  |
731 |  |
         /**
732 |  |
          * {@inheritDoc}
733 |  |
          */
734 |  |
         public long getLong(String key)
735 |  |
         {
736 | 15 |
             Long l = getLong(key, null);
737 | 13 |
             if (l != null)
738 |  |
             {
739 | 11 |
                 return l.longValue();
740 |  |
             }
741 |  |
             else
742 |  |
             {
743 | 2 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
744 |  |
             }
745 |  |
         }
746 |  |
747 |  |
         /**
748 |  |
          * {@inheritDoc}
749 |  |
          */
750 |  |
         public long getLong(String key, long defaultValue)
751 |  |
         {
752 | 7 |
             return getLong(key, new Long(defaultValue)).longValue();
753 |  |
         }
754 |  |
755 |  |
         /**
756 |  |
          * {@inheritDoc}
757 |  |
          */
758 |  |
         public Long getLong(String key, Long defaultValue)
759 |  |
         {
760 | 26 |
             Object value = resolveContainerStore(key);
761 |  |
762 | 26 |
             if (value == null)
763 |  |
             {
764 | 7 |
                 return defaultValue;
765 |  |
             }
766 |  |
             else
767 |  |
             {
768 |  |
                 try
769 |  |
                 {
770 | 19 |
                     return PropertyConverter.toLong(interpolate(value));
771 |  |
                 }
772 |  |
                 catch (ConversionException e)
773 |  |
                 {
774 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Long object", e);
775 |  |
                 }
776 |  |
             }
777 |  |
         }
778 |  |
779 |  |
         /**
780 |  |
          * {@inheritDoc}
781 |  |
          */
782 |  |
         public short getShort(String key)
783 |  |
         {
784 | 17 |
             Short s = getShort(key, null);
785 | 15 |
             if (s != null)
786 |  |
             {
787 | 13 |
                 return s.shortValue();
788 |  |
             }
789 |  |
             else
790 |  |
             {
791 | 2 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
792 |  |
             }
793 |  |
         }
794 |  |
795 |  |
         /**
796 |  |
          * {@inheritDoc}
797 |  |
          */
798 |  |
         public short getShort(String key, short defaultValue)
799 |  |
         {
800 | 7 |
             return getShort(key, new Short(defaultValue)).shortValue();
801 |  |
         }
802 |  |
803 |  |
         /**
804 |  |
          * {@inheritDoc}
805 |  |
          */
806 |  |
         public Short getShort(String key, Short defaultValue)
807 |  |
         {
808 | 31 |
             Object value = resolveContainerStore(key);
809 |  |
810 | 31 |
             if (value == null)
811 |  |
             {
812 | 9 |
                 return defaultValue;
813 |  |
             }
814 |  |
             else
815 |  |
             {
816 |  |
                 try
817 |  |
                 {
818 | 22 |
                     return PropertyConverter.toShort(interpolate(value));
819 |  |
                 }
820 |  |
                 catch (ConversionException e)
821 |  |
                 {
822 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a Short object", e);
823 |  |
                 }
824 |  |
             }
825 |  |
         }
826 |  |
827 |  |
         /**
828 |  |
          * {@inheritDoc}
829 |  |
          */
830 |  |
         public BigDecimal getBigDecimal(String key)
831 |  |
         {
832 | 7 |
             BigDecimal number = getBigDecimal(key, null);
833 | 5 |
             if (number != null)
834 |  |
             {
835 | 3 |
                 return number;
836 |  |
             }
837 | 2 |
             else if (isThrowExceptionOnMissing())
838 |  |
             {
839 | 1 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
840 |  |
             }
841 |  |
             else
842 |  |
             {
843 | 1 |
                 return null;
844 |  |
             }
845 |  |
         }
846 |  |
847 |  |
         /**
848 |  |
          * {@inheritDoc}
849 |  |
          */
850 |  |
         public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
851 |  |
         {
852 | 12 |
             Object value = resolveContainerStore(key);
853 |  |
854 | 12 |
             if (value == null)
855 |  |
             {
856 | 4 |
                 return defaultValue;
857 |  |
             }
858 |  |
             else
859 |  |
             {
860 |  |
                 try
861 |  |
                 {
862 | 8 |
                     return PropertyConverter.toBigDecimal(interpolate(value));
863 |  |
                 }
864 |  |
                 catch (ConversionException e)
865 |  |
                 {
866 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a BigDecimal object", e);
867 |  |
                 }
868 |  |
             }
869 |  |
         }
870 |  |
871 |  |
         /**
872 |  |
          * {@inheritDoc}
873 |  |
          */
874 |  |
         public BigInteger getBigInteger(String key)
875 |  |
         {
876 | 8 |
             BigInteger number = getBigInteger(key, null);
877 | 6 |
             if (number != null)
878 |  |
             {
879 | 4 |
                 return number;
880 |  |
             }
881 | 2 |
             else if (isThrowExceptionOnMissing())
882 |  |
             {
883 | 1 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
884 |  |
             }
885 |  |
             else
886 |  |
             {
887 | 1 |
                 return null;
888 |  |
             }
889 |  |
         }
890 |  |
891 |  |
         /**
892 |  |
          * {@inheritDoc}
893 |  |
          */
894 |  |
         public BigInteger getBigInteger(String key, BigInteger defaultValue)
895 |  |
         {
896 | 13 |
             Object value = resolveContainerStore(key);
897 |  |
898 | 13 |
             if (value == null)
899 |  |
             {
900 | 4 |
                 return defaultValue;
901 |  |
             }
902 |  |
             else
903 |  |
             {
904 |  |
                 try
905 |  |
                 {
906 | 9 |
                     return PropertyConverter.toBigInteger(interpolate(value));
907 |  |
                 }
908 |  |
                 catch (ConversionException e)
909 |  |
                 {
910 | 2 |
                     throw new ConversionException('\'' + key + "' doesn't map to a BigDecimal object", e);
911 |  |
                 }
912 |  |
             }
913 |  |
         }
914 |  |
915 |  |
         /**
916 |  |
          * {@inheritDoc}
917 |  |
          */
918 |  |
         public String getString(String key)
919 |  |
         {
920 | 511 |
             String s = getString(key, null);
921 | 509 |
             if (s != null)
922 |  |
             {
923 | 309 |
                 return s;
924 |  |
             }
925 | 200 |
             else if (isThrowExceptionOnMissing())
926 |  |
             {
927 | 7 |
                 throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
928 |  |
             }
929 |  |
             else
930 |  |
             {
931 | 193 |
                 return null;
932 |  |
             }
933 |  |
         }
934 |  |
935 |  |
         /**
936 |  |
          * {@inheritDoc}
937 |  |
          */
938 |  |
         public String getString(String key, String defaultValue)
939 |  |
         {
940 | 587 |
             Object value = resolveContainerStore(key);
941 |  |
942 | 587 |
             if (value instanceof String)
943 |  |
             {
944 | 379 |
                 return interpolate((String) value);
945 |  |
             }
946 | 208 |
             else if (value == null)
947 |  |
             {
948 | 208 |
                 return interpolate(defaultValue);
949 |  |
             }
950 |  |
             else
951 |  |
             {
952 | 0 |
                 throw new ConversionException('\'' + key + "' doesn't map to a String object");
953 |  |
             }
954 |  |
         }
955 |  |
956 |  |
         /**
957 |  |
          * {@inheritDoc}
958 |  |
          */
959 |  |
         public String[] getStringArray(String key)
960 |  |
         {
961 | 18 |
             Object value = getProperty(key);
962 |  |
963 |  |
             String[] array;
964 |  |
965 | 18 |
             if (value instanceof String)
966 |  |
             {
967 | 10 |
                 array = new String[1];
968 |  |
969 | 10 |
                 array[0] = interpolate((String) value);
970 |  |
             }
971 | 8 |
             else if (value instanceof List)
972 |  |
             {
973 | 6 |
                 List list = (List) value;
974 | 6 |
                 array = new String[list.size()];
975 |  |
976 | 22 |
                 for (int i = 0; i < array.length; i++)
977 |  |
                 {
978 | 16 |
                     array[i] = interpolate((String) list.get(i));
979 |  |
                 }
980 |  |
             }
981 | 2 |
             else if (value == null)
982 |  |
             {
983 | 2 |
                 array = new String[0];
984 |  |
             }
985 |  |
             else
986 |  |
             {
987 | 0 |
                 throw new ConversionException('\'' + key + "' doesn't map to a String/List object");
988 |  |
             }
989 | 18 |
             return array;
990 |  |
         }
991 |  |
992 |  |
         /**
993 |  |
          * {@inheritDoc}
994 |  |
          */
995 |  |
         public List getList(String key)
996 |  |
         {
997 | 247 |
             return getList(key, new ArrayList());
998 |  |
         }
999 |  |
1000 |  |
         /**
1001 |  |
          * {@inheritDoc}
1002 |  |
          */
1003 |  |
         public List getList(String key, List defaultValue)
1004 |  |
         {
1005 | 207 |
             Object value = getProperty(key);
1006 |  |
             List list;
1007 |  |
1008 | 207 |
             if (value instanceof String)
1009 |  |
             {
1010 | 49 |
                 list = new ArrayList(1);
1011 | 49 |
                 list.add(interpolate((String) value));
1012 |  |
             }
1013 | 158 |
             else if (value instanceof List)
1014 |  |
             {
1015 | 106 |
                 list = new ArrayList();
1016 | 106 |
                 List l = (List) value;
1017 |  |
1018 |  |
                 // add the interpolated elements in the new list
1019 | 106 |
                 Iterator it = l.iterator();
1020 | 581 |
                 while (it.hasNext())
1021 |  |
                 {
1022 | 369 |
                     list.add(interpolate(it.next()));
1023 |  |
                 }
1024 |  |
1025 |  |
             }
1026 | 52 |
             else if (value == null)
1027 |  |
             {
1028 | 51 |
                 list = defaultValue;
1029 |  |
             }
1030 |  |
             else
1031 |  |
             {
1032 | 1 |
                 throw new ConversionException('\'' + key + "' doesn't map to a List object: " + value + ", a "
1033 |  |
                         + value.getClass().getName());
1034 |  |
             }
1035 | 206 |
             return list;
1036 |  |
         }
1037 |  |
1038 |  |
         /**
1039 |  |
          * Returns an object from the store described by the key. If the value is a
1040 |  |
          * List object, replace it with the first object in the list.
1041 |  |
          *
1042 |  |
          * @param key The property key.
1043 |  |
          *
1044 |  |
          * @return value Value, transparently resolving a possible List dependency.
1045 |  |
          */
1046 |  |
         protected Object resolveContainerStore(String key)
1047 |  |
         {
1048 | 1030 |
             Object value = getProperty(key);
1049 | 1030 |
             if (value != null)
1050 |  |
             {
1051 | 733 |
                 if (value instanceof List)
1052 |  |
                 {
1053 | 11 |
                     List list = (List) value;
1054 | 11 |
                     value = list.isEmpty() ? null : list.get(0);
1055 |  |
                 }
1056 | 722 |
                 else if (value instanceof Object[])
1057 |  |
                 {
1058 | 1 |
                     Object[] array = (Object[]) value;
1059 | 1 |
                     value = array.length == 0 ? null : array[0];
1060 |  |
                 }
1061 | 721 |
                 else if (value instanceof boolean[])
1062 |  |
                 {
1063 | 1 |
                     boolean[] array = (boolean[]) value;
1064 | 1 |
                     value = array.length == 0 ? null : array[0] ? Boolean.TRUE : Boolean.FALSE;
1065 |  |
                 }
1066 | 720 |
                 else if (value instanceof byte[])
1067 |  |
                 {
1068 | 1 |
                     byte[] array = (byte[]) value;
1069 | 1 |
                     value = array.length == 0 ? null : new Byte(array[0]);
1070 |  |
                 }
1071 | 719 |
                 else if (value instanceof short[])
1072 |  |
                 {
1073 | 1 |
                     short[] array = (short[]) value;
1074 | 1 |
                     value = array.length == 0 ? null : new Short(array[0]);
1075 |  |
                 }
1076 | 718 |
                 else if (value instanceof int[])
1077 |  |
                 {
1078 | 1 |
                     int[] array = (int[]) value;
1079 | 1 |
                     value = array.length == 0 ? null : new Integer(array[0]);
1080 |  |
                 }
1081 | 717 |
                 else if (value instanceof long[])
1082 |  |
                 {
1083 | 1 |
                     long[] array = (long[]) value;
1084 | 1 |
                     value = array.length == 0 ? null : new Long(array[0]);
1085 |  |
                 }
1086 | 716 |
                 else if (value instanceof float[])
1087 |  |
                 {
1088 | 1 |
                     float[] array = (float[]) value;
1089 | 1 |
                     value = array.length == 0 ? null : new Float(array[0]);
1090 |  |
                 }
1091 | 715 |
                 else if (value instanceof double[])
1092 |  |
                 {
1093 | 1 |
                     double[] array = (double[]) value;
1094 | 1 |
                     value = array.length == 0 ? null : new Double(array[0]);
1095 |  |
                 }
1096 |  |
             }
1097 |  |
1098 | 1030 |
             return value;
1099 |  |
         }
1100 |  |
1101 |  |
     }