EMMA Coverage Report (generated Tue May 18 22:13:27 CDT 2004)
[all classes][org.apache.velocity.runtime.configuration]

COVERAGE SUMMARY FOR SOURCE FILE [Configuration.java]

nameclass, %method, %block, %line, %
Configuration.java100% (3/3)64%  (37/58)45%  (748/1666)51%  (186.5/368)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Configuration100% (1/1)60%  (32/53)42%  (658/1563)47%  (160.5/340)
combine (Configuration): void 0%   (0/1)0%   (0/18)0%   (0/4)
convertProperties (Properties): Configuration 0%   (0/1)0%   (0/23)0%   (0/5)
display (): void 0%   (0/1)0%   (0/28)0%   (0/6)
getBoolean (String, boolean): boolean 0%   (0/1)0%   (0/9)0%   (0/1)
getByte (String, byte): byte 0%   (0/1)0%   (0/9)0%   (0/1)
getDouble (String, double): double 0%   (0/1)0%   (0/9)0%   (0/1)
getExtendedProperties (): ExtendedProperties 0%   (0/1)0%   (0/3)0%   (0/1)
getFloat (String, float): float 0%   (0/1)0%   (0/9)0%   (0/1)
getInt (String, int): int 0%   (0/1)0%   (0/5)0%   (0/1)
getInteger (String, int): int 0%   (0/1)0%   (0/12)0%   (0/4)
getKeys (String): Iterator 0%   (0/1)0%   (0/29)0%   (0/7)
getLong (String, long): long 0%   (0/1)0%   (0/9)0%   (0/1)
getProperties (String): Properties 0%   (0/1)0%   (0/7)0%   (0/1)
getProperties (String, Properties): Properties 0%   (0/1)0%   (0/64)0%   (0/11)
getProperty (String): Object 0%   (0/1)0%   (0/16)0%   (0/5)
getShort (String, short): short 0%   (0/1)0%   (0/9)0%   (0/1)
getStringArray (String): String [] 0%   (0/1)0%   (0/71)0%   (0/15)
init (Configuration): void 0%   (0/1)0%   (0/4)0%   (0/2)
isInitialized (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
save (OutputStream, String): void 0%   (0/1)0%   (0/96)0%   (0/28)
setInclude (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
getVector (String, Vector): Vector 100% (1/1)16%  (10/62)23%  (3/13)
getString (String, String): String 100% (1/1)22%  (10/46)30%  (3/10)
clearProperty (String): void 100% (1/1)25%  (9/36)38%  (3/8)
testBoolean (String): String 100% (1/1)27%  (9/33)41%  (2.5/6)
getByte (String): byte 100% (1/1)42%  (10/24)75%  (3/4)
getDouble (String): double 100% (1/1)42%  (10/24)75%  (3/4)
getFloat (String): float 100% (1/1)42%  (10/24)75%  (3/4)
getInteger (String): int 100% (1/1)42%  (10/24)75%  (3/4)
getLong (String): long 100% (1/1)42%  (10/24)75%  (3/4)
getShort (String): short 100% (1/1)42%  (10/24)75%  (3/4)
getByte (String, Byte): Byte 100% (1/1)43%  (23/53)50%  (6/12)
getDouble (String, Double): Double 100% (1/1)43%  (23/53)50%  (6/12)
getFloat (String, Float): Float 100% (1/1)43%  (23/53)50%  (6/12)
getInteger (String, Integer): Integer 100% (1/1)43%  (23/53)50%  (6/12)
getLong (String, Long): Long 100% (1/1)43%  (23/53)50%  (6/12)
getShort (String, Short): Short 100% (1/1)43%  (23/53)50%  (6/12)
getBoolean (String): boolean 100% (1/1)44%  (11/25)75%  (3/4)
getBoolean (String, Boolean): Boolean 100% (1/1)47%  (27/57)54%  (7/13)
Configuration (String, String): void 100% (1/1)89%  (51/57)92%  (11/12)
load (InputStream): void 100% (1/1)90%  (97/108)85%  (17/20)
subset (String): Configuration 100% (1/1)92%  (54/59)88%  (14/16)
<static initializer> 100% (1/1)100% (3/3)100% (1/1)
Configuration (): void 100% (1/1)100% (20/20)100% (6/6)
Configuration (String): void 100% (1/1)100% (5/5)100% (2/2)
addProperty (String, Object): void 100% (1/1)100% (79/79)100% (18/18)
addStringProperty (String, String): void 100% (1/1)100% (47/47)100% (12/12)
getInclude (): String 100% (1/1)100% (2/2)100% (1/1)
getInt (String): int 100% (1/1)100% (4/4)100% (1/1)
getKeys (): Iterator 100% (1/1)100% (4/4)100% (1/1)
getString (String): String 100% (1/1)100% (5/5)100% (1/1)
getVector (String): Vector 100% (1/1)100% (5/5)100% (1/1)
setProperty (String, Object): void 100% (1/1)100% (8/8)100% (3/3)
     
class Configuration$PropertiesReader100% (1/1)100% (2/2)75%  (40/53)87%  (13/15)
readProperty (): String 100% (1/1)72%  (33/46)83%  (10/12)
Configuration$PropertiesReader (Configuration, Reader): void 100% (1/1)100% (7/7)100% (3/3)
     
class Configuration$PropertiesTokenizer100% (1/1)100% (3/3)100% (50/50)100% (13/13)
Configuration$PropertiesTokenizer (Configuration, String): void 100% (1/1)100% (8/8)100% (3/3)
hasMoreTokens (): boolean 100% (1/1)100% (3/3)100% (1/1)
nextToken (): String 100% (1/1)100% (39/39)100% (9/9)

1package org.apache.velocity.runtime.configuration;
2 
3/*
4 * Copyright (c) 2001 The Java Apache Project.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * 3. All advertising materials mentioning features or use of this
19 *    software must display the following acknowledgment:
20 *    "This product includes software developed by the Java Apache
21 *    Project for use in the Apache JServ servlet engine project
22 *    <http://java.apache.org/>."
23 *
24 * 4. The names "Apache JServ", "Apache JServ Servlet Engine", "Turbine",
25 *    "Apache Turbine", "Turbine Project", "Apache Turbine Project" and
26 *    "Java Apache Project" must not be used to endorse or promote products
27 *    derived from this software without prior written permission.
28 *
29 * 5. Products derived from this software may not be called "Apache JServ"
30 *    nor may "Apache" nor "Apache JServ" appear in their names without
31 *    prior written permission of the Java Apache Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 *    acknowledgment:
35 *    "This product includes software developed by the Java Apache
36 *    Project for use in the Apache JServ servlet engine project
37 *    <http://java.apache.org/>."
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 *
52 * This software consists of voluntary contributions made by many
53 * individuals on behalf of the Java Apache Group. For more information
54 * on the Java Apache Project and the Apache JServ Servlet Engine project,
55 * please see <http://java.apache.org/>.
56 *
57 */
58 
59import java.io.IOException;
60import java.io.File;
61import java.io.FileInputStream;
62import java.io.InputStream;
63import java.io.InputStreamReader;
64import java.io.LineNumberReader;
65import java.io.OutputStream;
66import java.io.PrintWriter;
67import java.io.Reader;
68 
69import java.util.ArrayList;
70import java.util.Enumeration;
71import java.util.Hashtable;
72import java.util.Iterator;
73import java.util.NoSuchElementException;
74import java.util.Properties;
75import java.util.StringTokenizer;
76import java.util.Vector;
77 
78import org.apache.commons.collections.ExtendedProperties;
79 
80/**
81 * This class extends normal Java properties by adding the possibility
82 * to use the same key many times concatenating the value strings
83 * instead of overwriting them.
84 *
85 * <p>The Extended Properties syntax is explained here:
86 *
87 * <ul>
88 *  <li>
89 *   Each property has the syntax <code>key = value</code>
90 *  </li>
91 *  <li>
92 *   The <i>key</i> may use any character but the equal sign '='.
93 *  </li>
94 *  <li>
95 *   <i>value</i> may be separated on different lines if a backslash
96 *   is placed at the end of the line that continues below.
97 *  </li>
98 *  <li>
99 *   If <i>value</i> is a list of strings, each token is separated
100 *   by a comma ','.
101 *  </li>
102 *  <li>
103 *   Commas in each token are escaped placing a backslash right before
104 *   the comma.
105 *  </li>
106 *  <li>
107 *   If a <i>key</i> is used more than once, the values are appended
108 *   like if they were on the same line separated with commas.
109 *  </li>
110 *  <li>
111 *   Blank lines and lines starting with character '#' are skipped.
112 *  </li>
113 *  <li>
114 *   If a property is named "include" (or whatever is defined by
115 *   setInclude() and getInclude() and the value of that property is
116 *   the full path to a file on disk, that file will be included into
117 *   the ConfigurationsRepository. You can also pull in files relative
118 *   to the parent configuration file. So if you have something
119 *   like the following:
120 *
121 *   include = additional.properties
122 *
123 *   Then "additional.properties" is expected to be in the same
124 *   directory as the parent configuration file.
125 * 
126 *   Duplicate name values will be replaced, so be careful.
127 *
128 *  </li>
129 * </ul>
130 *
131 * <p>Here is an example of a valid extended properties file:
132 *
133 * <p><pre>
134 *      # lines starting with # are comments
135 *
136 *      # This is the simplest property
137 *      key = value
138 *
139 *      # A long property may be separated on multiple lines
140 *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
141 *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
142 *
143 *      # This is a property with many tokens
144 *      tokens_on_a_line = first token, second token
145 *
146 *      # This sequence generates exactly the same result
147 *      tokens_on_multiple_lines = first token
148 *      tokens_on_multiple_lines = second token
149 *
150 *      # commas may be escaped in tokens
151 *      commas.excaped = Hi\, what'up?
152 * </pre>
153 *
154 * <p><b>NOTE</b>: this class has <b>not</b> been written for
155 * performance nor low memory usage.  In fact, it's way slower than it
156 * could be and generates too much memory garbage.  But since
157 * performance is not an issue during intialization (and there is not
158 * much time to improve it), I wrote it this way.  If you don't like
159 * it, go ahead and tune it up!
160 *
161 *
162 * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
163 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
164 * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
165 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
166 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
167 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
168 * @author <a href="mailto:kjohnson@transparent.com>Kent Johnson</a>
169 * @version $Id: Configuration.java,v 1.34 2003/05/04 17:14:37 geirm Exp $
170 *
171 * @deprecated As of version 1.1, please use ExtendedProperties from
172 * the Jakarta Commons Collections component.
173 */
174public class Configuration extends Hashtable
175{
176    // $$$ GMJ : remove post version 1.1
177    // intended to help deprecate this class w/o having to modify 
178    // the jakarta commons collections class which contains
179    // extended properties.  We need this when someone wants to 
180    // configure velocity w/ a Configuration : the strategy is simply
181    // to shadow the Configuration with the EP
182    private ExtendedProperties deprecationCrutch = new ExtendedProperties();
183 
184 
185    /**
186     * Default configurations repository.
187     */
188    private Configuration defaults;
189 
190    /**
191     * The file connected to this repository (holding comments and
192     * such).
193     *
194     * @serial
195     */
196    protected String file;
197 
198    /**
199     * Base path of the configuration file used to create
200     * this Configuration object.
201     */
202    protected String basePath;
203 
204    /**
205     * File separator.
206     */
207    protected String fileSeparator = System.getProperty("file.separator");
208 
209    /**
210     * Has this configuration been intialized.
211     */
212    protected boolean isInitialized = false;
213 
214    /**
215     * This is the name of the property that can point to other
216     * properties file for including other properties files.
217     */
218    protected static String include = "include";
219 
220    /**
221     * These are the keys in the order they listed
222     * in the configuration file. This is useful when
223     * you wish to perform operations with configuration
224     * information in a particular order.
225     */
226    protected ArrayList keysAsListed = new ArrayList();
227 
228    /**
229     * This class is used to read properties lines.  These lines do
230     * not terminate with new-line chars but rather when there is no
231     * backslash sign a the end of the line.  This is used to
232     * concatenate multiple lines for readability.
233     */
234    class PropertiesReader extends LineNumberReader
235    {
236        /**
237         * Constructor.
238         *
239         * @param reader A Reader.
240         */
241        public PropertiesReader(Reader reader)
242        {
243            super(reader);
244        }
245 
246        /**
247         * Read a property.
248         *
249         * @return A String.
250         * @exception IOException.
251         */
252        public String readProperty() throws IOException
253        {
254            StringBuffer buffer = new StringBuffer();
255 
256            try
257            {
258                while (true)
259                {
260                    String line = readLine().trim();
261                    if ((line.length() != 0) && (line.charAt(0) != '#'))
262                    {
263                        if (line.endsWith("\\"))
264                        {
265                            line = line.substring(0, line.length() - 1);
266                            buffer.append(line);
267                        }
268                        else
269                        {
270                            buffer.append(line);
271                            break;
272                        }
273                    }
274                }
275            }
276            catch (NullPointerException e)
277            {
278                return null;
279            }
280 
281            return buffer.toString();
282        }
283    }
284 
285    /**
286     * This class divides into tokens a property value.  Token
287     * separator is "," but commas into the property value are escaped
288     * using the backslash in front.
289     */
290    class PropertiesTokenizer extends StringTokenizer
291    {
292        /**
293         * The property delimiter used while parsing (a comma).
294         */
295        static final String DELIMITER = ",";
296 
297        /**
298         * Constructor.
299         *
300         * @param string A String.
301         */
302        public PropertiesTokenizer(String string)
303        {
304            super(string, DELIMITER);
305        }
306 
307        /**
308         * Check whether the object has more tokens.
309         *
310         * @return True if the object has more tokens.
311         */
312        public boolean hasMoreTokens()
313        {
314            return super.hasMoreTokens();
315        }
316 
317        /**
318         * Get next token.
319         *
320         * @return A String.
321         */
322        public String nextToken()
323        {
324            StringBuffer buffer = new StringBuffer();
325 
326            while (hasMoreTokens())
327            {
328                String token = super.nextToken();
329                if (token.endsWith("\\"))
330                {
331                    buffer.append(token.substring(0, token.length() - 1));
332                    buffer.append(DELIMITER);
333                }
334                else
335                {
336                    buffer.append(token);
337                    break;
338                }
339            }
340 
341            return buffer.toString().trim();
342        }
343    }
344 
345    /**
346     * Creates an empty extended properties object.
347     */
348    public Configuration ()
349    {
350        super();
351    }
352 
353    /**
354     * Creates and loads the extended properties from the specified
355     * file.
356     *
357     * @param file A String.
358     * @exception IOException.
359     */
360    public Configuration (String file) throws IOException
361    {
362        this(file,null);
363    }
364 
365    /**
366     * Creates and loads the extended properties from the specified
367     * file.
368     *
369     * @param file A String.
370     * @exception IOException.
371     */
372    public Configuration (String file, String defaultFile)
373        throws IOException
374    {
375        this.file = file;
376        
377        basePath = new File(file).getAbsolutePath();
378        basePath = basePath.substring(0, basePath.lastIndexOf(fileSeparator) + 1);
379        
380        this.load(new FileInputStream(file));
381        
382        if (defaultFile != null)
383        {
384            defaults = new Configuration(defaultFile);
385        }            
386    }
387 
388    /**
389     * Private initializer method that sets up the generic
390     * resources.
391     *
392     * @exception IOException, if there was an I/O problem.
393     */
394    private void init( Configuration exp ) throws IOException
395    {
396        isInitialized = true;
397    }
398    
399    /**
400     * Indicate to client code whether property
401     * resources have been initialized or not.
402     */
403    public boolean isInitialized()
404    {
405        return isInitialized;
406    }        
407 
408    /**
409     * Gets the property value for including other properties files.
410     * By default it is "include".
411     *
412     * @return A String.
413     */
414    public String getInclude()
415    {
416        return Configuration.include;
417    }
418 
419    /**
420     * Sets the property value for including other properties files.
421     * By default it is "include".
422     *
423     * @param inc A String.
424     */
425    public void setInclude(String inc)
426    {
427                Configuration.include = inc;
428    }
429 
430    /**
431     * Load the properties from the given input stream.
432     *
433     * @param input An InputStream.
434     * @exception IOException.
435     */
436    public synchronized void load(InputStream input)
437        throws IOException
438    {
439        PropertiesReader reader =
440            new PropertiesReader(new InputStreamReader(input));
441 
442        try
443        {
444            while (true)
445            {
446                String line = reader.readProperty();
447                int equalSign = line.indexOf('=');
448 
449                if (equalSign > 0)
450                {
451                    String key = line.substring(0, equalSign).trim();
452                    String value = line.substring(equalSign + 1).trim();
453 
454                    /*
455                     * Configure produces lines like this ... just
456                     * ignore them.
457                     */
458                    if ("".equals(value))
459                        continue;
460 
461                    if (getInclude() != null && 
462                        key.equalsIgnoreCase(getInclude()))
463                    {
464                        /*
465                         * Recursively load properties files.
466                         */
467                        File file = null;
468                        
469                        if (value.startsWith(fileSeparator))
470                        {
471                            /*
472                             * We have an absolute path so we'll
473                             * use this.
474                             */
475                            file = new File(value);
476                        }
477                        else
478                        {   
479                            /* 
480                             * We have a relative path, and we have
481                             * two possible forms here. If we have the
482                             * "./" form then just strip that off first
483                             * before continuing.
484                             */
485                            if (value.startsWith("." + fileSeparator))
486                            {
487                                value = value.substring(2);
488                            }
489                            
490                            file = new File(basePath + value);
491                        }
492                        
493                        if (file != null && file.exists() && file.canRead())
494                        {
495                            load ( new FileInputStream(file));
496                        }
497                    }
498                    else
499                    {
500                        addProperty(key,value);
501                        //setProperty(key,value);
502                    }                       
503                }
504            }
505        }
506        catch (NullPointerException e)
507        {
508            /*
509             * Should happen only when EOF is reached.
510             */
511            return;
512        }
513    }
514 
515    /**
516     *  Gets a property from the configuration.
517     *
518     *  @param key property to retrieve
519     *  @return value as object. Will return user value if exists,
520     *          if not then default value if exists, otherwise null
521     */
522    public Object getProperty( String key)
523    {
524        /*
525         *  first, try to get from the 'user value' store
526         */
527        Object o = this.get(key);
528 
529        if ( o == null)
530        {
531            /*
532             *  if there isn't a value there, get it from the
533             *  defaults if we have them
534             */
535            if (defaults != null)
536            {
537                o = defaults.get(key);
538            }
539        }
540 
541        return o;
542    }
543    
544    /**
545     * Add a property to the configuration. If it already
546     * exists then the value stated here will be added
547     * to the configuration entry. For example, if
548     *
549     * resource.loader = file
550     *
551     * is already present in the configuration and you
552     *
553     * addProperty("resource.loader", "classpath")
554     *
555     * Then you will end up with a Vector like the
556     * following:
557     *
558     * ["file", "classpath"]
559     *
560     * @param String key
561     * @param String value
562     */
563    //public void setProperty(String key, Object token)
564    public void addProperty(String key, Object token)
565    {
566 
567        // $$$ GMJ : remove after 1.1 release
568        // for deprecation help
569        deprecationCrutch.addProperty( key, token );
570 
571        Object o = this.get(key);
572 
573        /*
574         *  $$$ GMJ
575         *  FIXME : post 1.0 release, we need to not assume
576         *  that a scalar is a String - it can be an Object
577         *  so we should make a little vector-like class
578         *  say, Foo that wraps (not extends Vector),
579         *  so we can do things like
580         *  if ( !( o instanceof Foo) )
581         *  so we know it's our 'vector' container
582         *
583         *  This applies throughout
584         */
585        
586        if (o instanceof String)
587        {
588            Vector v = new Vector(2);
589            v.addElement(o);
590            v.addElement(token);
591            put(key, v);
592        }
593        else if (o instanceof Vector)
594        {
595            ((Vector) o).addElement(token);
596        }
597        else
598        {
599            /*
600             * This is the first time that we have seen
601             * request to place an object in the 
602             * configuration with the key 'key'. So
603             * we just want to place it directly into
604             * the configuration ... but we are going to
605             * make a special exception for String objects
606             * that contain "," characters. We will take
607             * CSV lists and turn the list into a vector of
608             * Strings before placing it in the configuration.
609             * This is a concession for Properties and the
610             * like that cannot parse multiple same key
611             * values.
612             */
613            if (token instanceof String &&
614                ((String)token).indexOf(PropertiesTokenizer.DELIMITER) > 0)
615            {
616                PropertiesTokenizer tokenizer = 
617                    new PropertiesTokenizer((String)token);
618                    
619                while (tokenizer.hasMoreTokens())
620                {
621                    String value = tokenizer.nextToken();
622                    
623                    /*
624                     * we know this is a string, so make sure it
625                     * just goes in rather than risking vectorization
626                     * if it contains an escaped comma
627                     */
628                    addStringProperty(key,value);
629                }
630            }
631            else
632            {
633                /*
634                 * We want to keep track of the order the keys
635                 * are parsed, or dynamically entered into
636                 * the configuration. So when we see a key
637                 * for the first time we will place it in
638                 * an ArrayList so that if a client class needs
639                 * to perform operations with configuration
640                 * in a definite order it will be possible.
641                 */
642 
643                /*
644                 * safety check
645                 */
646 
647                if( !containsKey( key ) )
648                {
649                    keysAsListed.add(key);
650                }
651 
652                /*
653                 * and the value
654                 */
655                put(key, token);
656            }                
657        }
658    }
659 
660 
661    /**
662     *  Sets a string property w/o checking for commas - used
663     *  internally when a property has been broken up into
664     *  strings that could contain escaped commas to prevent
665     *  the inadvertant vectorization.
666     *
667     *  Thanks to Leon Messerschmidt for this one.
668     *
669     */
670    private  void addStringProperty(String key, String token)
671    {
672        Object o = this.get(key);
673 
674        /*
675         *  $$$ GMJ
676         *  FIXME : post 1.0 release, we need to not assume
677         *  that a scalar is a String - it can be an Object
678         *  so we should make a little vector-like class
679         *  say, Foo that wraps (not extends Vector),
680         *  so we can do things like
681         *  if ( !( o instanceof Foo) )
682         *  so we know it's our 'vector' container
683         *
684         *  This applies throughout
685         */
686 
687        /*
688         *  do the usual thing - if we have a value and 
689         *  it's scalar, make a vector, otherwise add
690         *  to the vector
691         */
692 
693        if (o instanceof String)
694        {
695            Vector v = new Vector(2);
696            v.addElement(o);
697            v.addElement(token);
698            put(key, v);
699        }
700        else if (o instanceof Vector)
701        {
702            ((Vector) o).addElement(token);
703        }
704        else
705        {
706            if( !containsKey( key ) )
707            {
708                keysAsListed.add(key);
709            }
710 
711            put( key, token);
712        }
713    }
714 
715    /**
716     * Set a property, this will replace any previously
717     * set values. Set values is implicitly a call
718     * to clearProperty(key), addProperty(key,value).
719     *
720     * @param String key
721     * @param String value
722     */
723    public void setProperty(String key, Object value)
724    {
725        clearProperty(key);
726        addProperty(key,value);
727    }
728    
729    /**
730     * Save the properties to the given outputstream.
731     *
732     * @param output An OutputStream.
733     * @param header A String.
734     * @exception IOException.
735     */
736    public synchronized void save(OutputStream output,
737                                  String Header)
738        throws IOException
739    {
740        if(output != null)
741        {
742            PrintWriter theWrtr = new PrintWriter(output);
743            if(Header != null)
744            {
745                theWrtr.println(Header);
746            }
747            Enumeration theKeys = keys();
748            while(theKeys.hasMoreElements())
749            {
750                String key = (String) theKeys.nextElement();
751                Object value = get((Object) key);
752                if(value != null)
753                {
754                    if(value instanceof String)
755                    {
756                        StringBuffer currentOutput = new StringBuffer();
757                        currentOutput.append(key);
758                        currentOutput.append("=");
759                        currentOutput.append((String) value);
760                        theWrtr.println(currentOutput.toString());
761                    }
762                    else if(value instanceof Vector)
763                    {
764                        Vector values = (Vector) value;
765                        Enumeration valuesEnum = values.elements();
766                        while(valuesEnum.hasMoreElements())
767                        {
768                            String currentElement = 
769                                   (String) valuesEnum.nextElement();
770                            StringBuffer currentOutput = new StringBuffer();
771                            currentOutput.append(key);
772                            currentOutput.append("=");
773                            currentOutput.append(currentElement);
774                            theWrtr.println(currentOutput.toString());
775                        }
776                    }
777                }    
778                theWrtr.println();
779                theWrtr.flush();
780            }    
781        }        
782    }
783 
784    /**
785     * Combines an existing Hashtable with this Hashtable.
786     *
787     * Warning: It will overwrite previous entries without warning.
788     *
789     * @param Configuration
790     */
791    public void combine (Configuration c)
792    {
793        for (Iterator i = c.getKeys() ; i.hasNext() ;)
794        {
795            String key = (String) i.next();
796            //clearProperty(key);
797            setProperty( key, c.get(key) );
798        }
799    }
800    
801    /**
802     * Clear a property in the configuration.
803     *
804     * @param String key to remove along with corresponding value.
805     */
806    public void clearProperty(String key)
807    {
808        // $$$ GMJ : remove after 1.1 release
809        // for deprecation help
810        deprecationCrutch.clearProperty( key  );
811 
812        if (containsKey(key))
813        {
814            /*
815             * we also need to rebuild the keysAsListed or else
816             * things get *very* confusing
817             */
818 
819            for(int i = 0; i < keysAsListed.size(); i++)
820            {
821                if ( ( (String) keysAsListed.get(i)).equals( key ) )
822                {
823                    keysAsListed.remove(i);
824                    break;
825                }
826            }
827 
828            remove(key);
829        }            
830    }
831 
832    /**
833     * Get the list of the keys contained in the configuration
834     * repository.
835     *
836     * @return An Iterator.
837     */
838    public Iterator getKeys()
839    {
840        return keysAsListed.iterator();
841    }
842 
843    /**
844     * Get the list of the keys contained in the configuration
845     * repository that match the specified prefix.
846     *
847     * @param prefix The prefix to test against.
848     * @return An Iterator of keys that match the prefix.
849     */
850    public Iterator getKeys(String prefix)
851    {
852        Iterator keys = getKeys();
853        ArrayList matchingKeys = new ArrayList();
854        
855        while( keys.hasNext() )
856        {
857            Object key = keys.next();
858            
859            if( key instanceof String && ((String) key).startsWith(prefix) )
860            {
861                matchingKeys.add(key);
862            }
863        }
864        return matchingKeys.iterator();
865    }
866 
867    /**
868     * Create a Configurations object that is a subset
869     * of this one. Take into account duplicate keys
870     * by using the setProperty() in Configuration.
871     *
872     * @param String prefix
873     */
874    public Configuration subset(String prefix)
875    {
876        Configuration c = new Configuration();
877        Iterator keys = getKeys();
878        boolean validSubset = false;
879        
880        while( keys.hasNext() )
881        {
882            Object key = keys.next();
883            
884            if( key instanceof String && ((String) key).startsWith(prefix) )
885            {
886                if (!validSubset)
887                {
888                    validSubset = true;
889                }
890                
891                String newKey = null;
892                
893                /*
894                 * Check to make sure that c.subset(prefix) doesn't
895                 * blow up when there is only a single property
896                 * with the key prefix. This is not a useful
897                 * subset but it is a valid subset.
898                 */
899                if ( ((String)key).length() == prefix.length())
900                {
901                    newKey = prefix;
902                }
903                else
904                {
905                    newKey = ((String)key).substring(prefix.length() + 1);
906                }                    
907                
908                /*
909                 * Make sure to use the setProperty() method and not
910                 * just put(). setProperty() takes care of catching
911                 * all the keys in the order they appear in a
912                 * properties files or the order they are set
913                 * dynamically.
914                 */
915 
916                c.setProperty(newKey, get(key));
917            }
918        }
919        
920        if (validSubset)
921        {
922            return c;
923        }
924        else
925        {
926            return null;
927        }
928    }
929 
930    /**
931     * Display the configuration for debugging
932     * purposes.
933     */
934    public void display()
935    {
936        Iterator i = getKeys();
937        
938        while (i.hasNext())
939        {
940            String key = (String) i.next();
941            Object value = get(key);
942            System.out.println(key + " => " + value);
943        }
944    }     
945 
946    /**
947     * Get a string associated with the given configuration key.
948     *
949     * @param key The configuration key.
950     * @return The associated string.
951     * @exception ClassCastException is thrown if the key maps to an
952     * object that is not a String.
953     */
954    public String getString(String key)
955    {
956        return getString(key, null);
957    }
958 
959    /**
960     * Get a string associated with the given configuration key.
961     *
962     * @param key The configuration key.
963     * @param defaultValue The default value.
964     * @return The associated string if key is found,
965     * default value otherwise.
966     * @exception ClassCastException is thrown if the key maps to an
967     * object that is not a String.
968     */
969    public String getString(String key,
970                            String defaultValue)
971    {
972        Object value = get(key);
973 
974        if (value instanceof String)
975        {
976            return (String) value;
977        }
978        else if (value == null)
979        {
980            if (defaults != null)
981            {
982                return defaults.getString(key, defaultValue);
983            }
984            else
985            {
986                return defaultValue;
987            }
988        }
989        else if (value instanceof Vector)
990        {
991            return (String) ((Vector) value).get(0);
992        }
993        else
994        {
995            throw new ClassCastException(
996                '\'' + key + "' doesn't map to a String object");
997        }
998    }
999 
1000    /**
1001     * Get a list of properties associated with the given
1002     * configuration key.
1003     *
1004     * @param key The configuration key.
1005     * @return The associated properties if key is found.
1006     * @exception ClassCastException is thrown if the key maps to an
1007     * object that is not a String/Vector.
1008     * @exception IllegalArgumentException if one of the tokens is
1009     * malformed (does not contain an equals sign).
1010     */
1011    public Properties getProperties(String key)
1012    {
1013        return getProperties(key, new Properties());
1014    }
1015 
1016    /**
1017     * Get a list of properties associated with the given
1018     * configuration key.
1019     *
1020     * @param key The configuration key.
1021     * @return The associated properties if key is found.
1022     * @exception ClassCastException is thrown if the key maps to an
1023     * object that is not a String/Vector.
1024     * @exception IllegalArgumentException if one of the tokens is
1025     * malformed (does not contain an equals sign).
1026     */
1027    public Properties getProperties(String key,
1028                                    Properties defaults)
1029    {
1030        /*
1031         * Grab an array of the tokens for this key.
1032         */
1033        String[] tokens = getStringArray(key);
1034 
1035        /* 
1036         * Each token is of the form 'key=value'.
1037         */
1038        Properties props = new Properties(defaults);
1039        for (int i = 0; i < tokens.length; i++)
1040        {
1041            String token = tokens[i];
1042            int equalSign = token.indexOf('=');
1043            if (equalSign > 0)
1044            {
1045                String pkey = token.substring(0, equalSign).trim();
1046                String pvalue = token.substring(equalSign + 1).trim();
1047                props.put(pkey, pvalue);
1048            }
1049            else
1050            {
1051                throw new IllegalArgumentException('\'' + token +
1052                                                   "' does not contain " +
1053                                                   "an equals sign");
1054            }
1055        }
1056        return props;
1057    }
1058 
1059    /**
1060     * Get an array of strings associated with the given configuration
1061     * key.
1062     *
1063     * @param key The configuration key.
1064     * @return The associated string array if key is found.
1065     * @exception ClassCastException is thrown if the key maps to an
1066     * object that is not a String/Vector.
1067     */
1068    public String[] getStringArray(String key)
1069    {
1070        Object value = get(key);
1071 
1072        // What's your vector, Victor?
1073        Vector vector;
1074        if (value instanceof String)
1075        {
1076            vector = new Vector(1);
1077            vector.addElement(value);
1078        }
1079        else if (value instanceof Vector)
1080        {
1081            vector = (Vector)value;
1082        }
1083        else if (value == null)
1084        {
1085            if (defaults != null)
1086            {
1087                return defaults.getStringArray(key);
1088            }
1089            else
1090            {
1091                return new String[0];
1092            }
1093        }
1094        else
1095        {
1096            throw new ClassCastException(
1097                '\'' + key + "' doesn't map to a String/Vector object");
1098        }
1099 
1100        String[] tokens = new String[vector.size()];
1101        for (int i = 0; i < tokens.length; i++)
1102        {
1103            tokens[i] = (String)vector.elementAt(i);
1104        }
1105 
1106        return tokens;
1107    }
1108 
1109    /**
1110     * Get a Vector of strings associated with the given configuration
1111     * key.
1112     *
1113     * @param key The configuration key.
1114     * @return The associated Vector.
1115     * @exception ClassCastException is thrown if the key maps to an
1116     * object that is not a Vector.
1117     */
1118    public Vector getVector(String key)
1119    {
1120        return getVector(key, null);
1121    }
1122 
1123    /**
1124     * Get a Vector of strings associated with the given configuration
1125     * key.
1126     *
1127     * @param key The configuration key.
1128     * @param defaultValue The default value.
1129     * @return The associated Vector.
1130     * @exception ClassCastException is thrown if the key maps to an
1131     * object that is not a Vector.
1132     */
1133    public Vector getVector(String key,
1134                            Vector defaultValue)
1135    {
1136        Object value = get(key);
1137 
1138        if (value instanceof Vector)
1139        {
1140            return (Vector) value;
1141        }
1142        else if (value instanceof String)
1143        {
1144            Vector v = new Vector(1);
1145            v.addElement((String) value);
1146            put(key, v);
1147            return v;
1148        }
1149        else if (value == null)
1150        {
1151            if (defaults != null)
1152            {
1153                return defaults.getVector(key, defaultValue);
1154            }
1155            else
1156            {
1157                return ((defaultValue == null) ?
1158                        new Vector() : defaultValue);
1159            }
1160        }
1161        else
1162        {
1163            throw new ClassCastException(
1164                '\'' + key + "' doesn't map to a Vector object");
1165        }
1166    }
1167 
1168    /**
1169     * Get a boolean associated with the given configuration key.
1170     *
1171     * @param key The configuration key.
1172     * @return The associated boolean.
1173     * @exception NoSuchElementException is thrown if the key doesn't
1174     * map to an existing object.
1175     * @exception ClassCastException is thrown if the key maps to an
1176     * object that is not a Boolean.
1177     */
1178    public boolean getBoolean(String key)
1179    {
1180        Boolean b = getBoolean(key, (Boolean) null);
1181        if (b != null)
1182        {
1183            return b.booleanValue();
1184        }
1185        else
1186        {
1187            throw new NoSuchElementException(
1188                '\'' + key + "' doesn't map to an existing object");
1189        }
1190    }
1191 
1192    /**
1193     * Get a boolean associated with the given configuration key.
1194     *
1195     * @param key The configuration key.
1196     * @param defaultValue The default value.
1197     * @return The associated boolean.
1198     * @exception ClassCastException is thrown if the key maps to an
1199     * object that is not a Boolean.
1200     */
1201    public boolean getBoolean(String key, boolean defaultValue)
1202    {
1203        return getBoolean(key, new Boolean(defaultValue)).booleanValue();
1204    }
1205 
1206    /**
1207     * Get a boolean associated with the given configuration key.
1208     *
1209     * @param key The configuration key.
1210     * @param defaultValue The default value.
1211     * @return The associated boolean if key is found and has valid
1212     * format, default value otherwise.
1213     * @exception ClassCastException is thrown if the key maps to an
1214     * object that is not a Boolean.
1215     */
1216    public Boolean getBoolean(String key, Boolean defaultValue)
1217    {
1218    
1219        Object value = get(key);
1220 
1221        if (value instanceof Boolean)
1222        {
1223            return (Boolean) value;
1224        }
1225        else if (value instanceof String)
1226        {
1227            String s = testBoolean((String)value);
1228            Boolean b = new Boolean(s);
1229            put(key, b);
1230            return b;
1231        }
1232        else if (value == null)
1233        {
1234            if (defaults != null)
1235            {
1236                return defaults.getBoolean(key, defaultValue);
1237            }
1238            else
1239            {
1240                return defaultValue;
1241            }
1242        }
1243        else
1244        {
1245            throw new ClassCastException(
1246                '\'' + key + "' doesn't map to a Boolean object");
1247        }
1248    }
1249    
1250    /**
1251     * Test whether the string represent by value maps to a boolean
1252     * value or not. We will allow <code>true</code>, <code>on</code>,
1253     * and <code>yes</code> for a <code>true</code> boolean value, and
1254     * <code>false</code>, <code>off</code>, and <code>no</code> for
1255     * <code>false</code> boolean values.  Case of value to test for
1256     * boolean status is ignored.
1257     *
1258     * @param String The value to test for boolean state.
1259     * @return <code>true</code> or <code>false</code> if the supplied
1260     * text maps to a boolean value, or <code>null</code> otherwise.
1261     */
1262    public String testBoolean(String value)
1263    {
1264        String s = ((String)value).toLowerCase();
1265    
1266        if (s.equals("true") || s.equals("on") || s.equals("yes"))
1267        {
1268            return "true";
1269        }
1270        else if (s.equals("false") || s.equals("off") || s.equals("no"))
1271        {
1272            return "false";
1273        }
1274        else
1275        {
1276            return null;
1277        }
1278    }
1279 
1280    /**
1281     * Get a byte associated with the given configuration key.
1282     *
1283     * @param key The configuration key.
1284     * @return The associated byte.
1285     * @exception NoSuchElementException is thrown if the key doesn't
1286     * map to an existing object.
1287     * @exception ClassCastException is thrown if the key maps to an
1288     * object that is not a Byte.
1289     * @exception NumberFormatException is thrown if the value mapped
1290     * by the key has not a valid number format.
1291     */
1292    public byte getByte(String key)
1293    {
1294        Byte b = getByte(key, null);
1295        if (b != null)
1296        {
1297            return b.byteValue();
1298        }
1299        else
1300        {
1301            throw new NoSuchElementException(
1302                '\'' + key + " doesn't map to an existing object");
1303        }
1304    }
1305 
1306    /**
1307     * Get a byte associated with the given configuration key.
1308     *
1309     * @param key The configuration key.
1310     * @param defaultValue The default value.
1311     * @return The associated byte.
1312     * @exception ClassCastException is thrown if the key maps to an
1313     * object that is not a Byte.
1314     * @exception NumberFormatException is thrown if the value mapped
1315     * by the key has not a valid number format.
1316     */
1317    public byte getByte(String key,
1318                        byte defaultValue)
1319    {
1320        return getByte(key, new Byte(defaultValue)).byteValue();
1321    }
1322 
1323    /**
1324     * Get a byte associated with the given configuration key.
1325     *
1326     * @param key The configuration key.
1327     * @param defaultValue The default value.
1328     * @return The associated byte if key is found and has valid
1329     * format, default value otherwise.
1330     * @exception ClassCastException is thrown if the key maps to an
1331     * object that is not a Byte.
1332     * @exception NumberFormatException is thrown if the value mapped
1333     * by the key has not a valid number format.
1334     */
1335    public Byte getByte(String key,
1336                        Byte defaultValue)
1337    {
1338        Object value = get(key);
1339 
1340        if (value instanceof Byte)
1341        {
1342            return (Byte) value;
1343        }
1344        else if (value instanceof String)
1345        {
1346            Byte b = new Byte((String) value);
1347            put(key, b);
1348            return b;
1349        }
1350        else if (value == null)
1351        {
1352            if (defaults != null)
1353            {
1354                return defaults.getByte(key, defaultValue);
1355            }
1356            else
1357            {
1358                return defaultValue;
1359            }
1360        }
1361        else
1362        {
1363            throw new ClassCastException(
1364                '\'' + key + "' doesn't map to a Byte object");
1365        }
1366    }
1367 
1368    /**
1369     * Get a short associated with the given configuration key.
1370     *
1371     * @param key The configuration key.
1372     * @return The associated short.
1373     * @exception NoSuchElementException is thrown if the key doesn't
1374     * map to an existing object.
1375     * @exception ClassCastException is thrown if the key maps to an
1376     * object that is not a Short.
1377     * @exception NumberFormatException is thrown if the value mapped
1378     * by the key has not a valid number format.
1379     */
1380    public short getShort(String key)
1381    {
1382        Short s = getShort(key, null);
1383        if (s != null)
1384        {
1385            return s.shortValue();
1386        }
1387        else
1388        {
1389            throw new NoSuchElementException(
1390                '\'' + key + "' doesn't map to an existing object");
1391        }
1392    }
1393 
1394    /**
1395     * Get a short associated with the given configuration key.
1396     *
1397     * @param key The configuration key.
1398     * @param defaultValue The default value.
1399     * @return The associated short.
1400     * @exception ClassCastException is thrown if the key maps to an
1401     * object that is not a Short.
1402     * @exception NumberFormatException is thrown if the value mapped
1403     * by the key has not a valid number format.
1404     */
1405    public short getShort(String key,
1406                          short defaultValue)
1407    {
1408        return getShort(key, new Short(defaultValue)).shortValue();
1409    }
1410 
1411    /**
1412     * Get a short associated with the given configuration key.
1413     *
1414     * @param key The configuration key.
1415     * @param defaultValue The default value.
1416     * @return The associated short if key is found and has valid
1417     * format, default value otherwise.
1418     * @exception ClassCastException is thrown if the key maps to an
1419     * object that is not a Short.
1420     * @exception NumberFormatException is thrown if the value mapped
1421     * by the key has not a valid number format.
1422     */
1423    public Short getShort(String key,
1424                          Short defaultValue)
1425    {
1426        Object value = get(key);
1427 
1428        if (value instanceof Short)
1429        {
1430            return (Short) value;
1431        }
1432        else if (value instanceof String)
1433        {
1434            Short s = new Short((String) value);
1435            put(key, s);
1436            return s;
1437        }
1438        else if (value == null)
1439        {
1440            if (defaults != null)
1441            {
1442                return defaults.getShort(key, defaultValue);
1443            }
1444            else
1445            {
1446                return defaultValue;
1447            }
1448        }
1449        else
1450        {
1451            throw new ClassCastException(
1452                '\'' + key + "' doesn't map to a Short object");
1453        }
1454    }
1455 
1456    /**
1457     * The purpose of this method is to get the configuration resource
1458     * with the given name as an integer.
1459     *
1460     * @param name The resource name.
1461     * @return The value of the resource as an integer.
1462     */
1463    public int getInt(String name)
1464    {
1465        return getInteger(name);
1466    }
1467 
1468    /**
1469     * The purpose of this method is to get the configuration resource
1470     * with the given name as an integer, or a default value.
1471     *
1472     * @param name The resource name
1473     * @param def The default value of the resource.
1474     * @return The value of the resource as an integer.
1475     */
1476    public int getInt(String name,
1477                      int def)
1478    {
1479        return getInteger(name, def);
1480    }
1481 
1482    /**
1483     * Get a int associated with the given configuration key.
1484     *
1485     * @param key The configuration key.
1486     * @return The associated int.
1487     * @exception NoSuchElementException is thrown if the key doesn't
1488     * map to an existing object.
1489     * @exception ClassCastException is thrown if the key maps to an
1490     * object that is not a Integer.
1491     * @exception NumberFormatException is thrown if the value mapped
1492     * by the key has not a valid number format.
1493     */
1494    public int getInteger(String key)
1495    {
1496        Integer i = getInteger(key, null);
1497        if (i != null)
1498        {
1499            return i.intValue();
1500        }
1501        else
1502        {
1503            throw new NoSuchElementException(
1504                '\'' + key + "' doesn't map to an existing object");
1505        }
1506    }
1507 
1508    /**
1509     * Get a int associated with the given configuration key.
1510     *
1511     * @param key The configuration key.
1512     * @param defaultValue The default value.
1513     * @return The associated int.
1514     * @exception ClassCastException is thrown if the key maps to an
1515     * object that is not a Integer.
1516     * @exception NumberFormatException is thrown if the value mapped
1517     * by the key has not a valid number format.
1518     */
1519    public int getInteger(String key,
1520                          int defaultValue)
1521    {    
1522        Integer i = getInteger(key, null);
1523        
1524        if (i == null)
1525        {
1526            return defaultValue;
1527        }
1528        
1529        return i.intValue();
1530      }
1531 
1532 
1533    /**
1534     * Get a int associated with the given configuration key.
1535     *
1536     * @param key The configuration key.
1537     * @param defaultValue The default value.
1538     * @return The associated int if key is found and has valid
1539     * format, default value otherwise.
1540     * @exception ClassCastException is thrown if the key maps to an
1541     * object that is not a Integer.
1542     * @exception NumberFormatException is thrown if the value mapped
1543     * by the key has not a valid number format.
1544     */
1545    public Integer getInteger(String key,
1546                              Integer defaultValue)
1547    {
1548        Object value = get(key);
1549 
1550        if (value instanceof Integer)
1551        {
1552            return (Integer) value;
1553        }
1554        else if (value instanceof String)
1555        {
1556            Integer i = new Integer((String) value);
1557            put(key, i);
1558            return i;
1559        }
1560        else if (value == null)
1561        {
1562            if (defaults != null)
1563            {
1564                return defaults.getInteger(key, defaultValue);
1565            }
1566            else
1567            {
1568                return defaultValue;
1569            }
1570        }
1571        else
1572        {
1573            throw new ClassCastException(
1574                '\'' + key + "' doesn't map to a Integer object");
1575        }
1576    }
1577 
1578    /**
1579     * Get a long associated with the given configuration key.
1580     *
1581     * @param key The configuration key.
1582     * @return The associated long.
1583     * @exception NoSuchElementException is thrown if the key doesn't
1584     * map to an existing object.
1585     * @exception ClassCastException is thrown if the key maps to an
1586     * object that is not a Long.
1587     * @exception NumberFormatException is thrown if the value mapped
1588     * by the key has not a valid number format.
1589     */
1590    public long getLong(String key)
1591    {
1592        Long l = getLong(key, null);
1593        if (l != null)
1594        {
1595            return l.longValue();
1596        }
1597        else
1598        {
1599            throw new NoSuchElementException(
1600                '\'' + key + "' doesn't map to an existing object");
1601        }
1602    }
1603 
1604    /**
1605     * Get a long associated with the given configuration key.
1606     *
1607     * @param key The configuration key.
1608     * @param defaultValue The default value.
1609     * @return The associated long.
1610     * @exception ClassCastException is thrown if the key maps to an
1611     * object that is not a Long.
1612     * @exception NumberFormatException is thrown if the value mapped
1613     * by the key has not a valid number format.
1614     */
1615    public long getLong(String key,
1616                        long defaultValue)
1617    {
1618        return getLong(key, new Long(defaultValue)).longValue();
1619    }
1620 
1621    /**
1622     * Get a long associated with the given configuration key.
1623     *
1624     * @param key The configuration key.
1625     * @param defaultValue The default value.
1626     * @return The associated long if key is found and has valid
1627     * format, default value otherwise.
1628     * @exception ClassCastException is thrown if the key maps to an
1629     * object that is not a Long.
1630     * @exception NumberFormatException is thrown if the value mapped
1631     * by the key has not a valid number format.
1632     */
1633    public Long getLong(String key,
1634                        Long defaultValue)
1635    {
1636        Object value = get(key);
1637 
1638        if (value instanceof Long)
1639        {
1640            return (Long) value;
1641        }
1642        else if (value instanceof String)
1643        {
1644            Long l = new Long((String) value);
1645            put(key, l);
1646            return l;
1647        }
1648        else if (value == null)
1649        {
1650            if (defaults != null)
1651            {
1652                return defaults.getLong(key, defaultValue);
1653            }
1654            else
1655            {
1656                return defaultValue;
1657            }
1658        }
1659        else
1660        {
1661            throw new ClassCastException(
1662                '\'' + key + "' doesn't map to a Long object");
1663        }
1664    }
1665 
1666    /**
1667     * Get a float associated with the given configuration key.
1668     *
1669     * @param key The configuration key.
1670     * @return The associated float.
1671     * @exception NoSuchElementException is thrown if the key doesn't
1672     * map to an existing object.
1673     * @exception ClassCastException is thrown if the key maps to an
1674     * object that is not a Float.
1675     * @exception NumberFormatException is thrown if the value mapped
1676     * by the key has not a valid number format.
1677     */
1678    public float getFloat(String key)
1679    {
1680        Float f = getFloat(key, null);
1681        if (f != null)
1682        {
1683            return f.floatValue();
1684        }
1685        else
1686        {
1687            throw new NoSuchElementException(
1688                '\'' + key + "' doesn't map to an existing object");
1689        }
1690    }
1691 
1692    /**
1693     * Get a float associated with the given configuration key.
1694     *
1695     * @param key The configuration key.
1696     * @param defaultValue The default value.
1697     * @return The associated float.
1698     * @exception ClassCastException is thrown if the key maps to an
1699     * object that is not a Float.
1700     * @exception NumberFormatException is thrown if the value mapped
1701     * by the key has not a valid number format.
1702     */
1703    public float getFloat(String key,
1704                          float defaultValue)
1705    {
1706        return getFloat(key, new Float(defaultValue)).floatValue();
1707    }
1708 
1709    /**
1710     * Get a float associated with the given configuration key.
1711     *
1712     * @param key The configuration key.
1713     * @param defaultValue The default value.
1714     * @return The associated float if key is found and has valid
1715     * format, default value otherwise.
1716     * @exception ClassCastException is thrown if the key maps to an
1717     * object that is not a Float.
1718     * @exception NumberFormatException is thrown if the value mapped
1719     * by the key has not a valid number format.
1720     */
1721    public Float getFloat(String key,
1722                          Float defaultValue)
1723    {
1724        Object value = get(key);
1725 
1726        if (value instanceof Float)
1727        {
1728            return (Float) value;
1729        }
1730        else if (value instanceof String)
1731        {
1732            Float f = new Float((String) value);
1733            put(key, f);
1734            return f;
1735        }
1736        else if (value == null)
1737        {
1738            if (defaults != null)
1739            {
1740                return defaults.getFloat(key, defaultValue);
1741            }
1742            else
1743            {
1744                return defaultValue;
1745            }
1746        }
1747        else
1748        {
1749            throw new ClassCastException(
1750                '\'' + key + "' doesn't map to a Float object");
1751        }
1752    }
1753 
1754    /**
1755     * Get a double associated with the given configuration key.
1756     *
1757     * @param key The configuration key.
1758     * @return The associated double.
1759     * @exception NoSuchElementException is thrown if the key doesn't
1760     * map to an existing object.
1761     * @exception ClassCastException is thrown if the key maps to an
1762     * object that is not a Double.
1763     * @exception NumberFormatException is thrown if the value mapped
1764     * by the key has not a valid number format.
1765     */
1766    public double getDouble(String key)
1767    {
1768        Double d = getDouble(key, null);
1769        if (d != null)
1770        {
1771            return d.doubleValue();
1772        }
1773        else
1774        {
1775            throw new NoSuchElementException(
1776                '\'' + key + "' doesn't map to an existing object");
1777        }
1778    }
1779 
1780    /**
1781     * Get a double associated with the given configuration key.
1782     *
1783     * @param key The configuration key.
1784     * @param defaultValue The default value.
1785     * @return The associated double.
1786     * @exception ClassCastException is thrown if the key maps to an
1787     * object that is not a Double.
1788     * @exception NumberFormatException is thrown if the value mapped
1789     * by the key has not a valid number format.
1790     */
1791    public double getDouble(String key,
1792                            double defaultValue)
1793    {
1794        return getDouble(key, new Double(defaultValue)).doubleValue();
1795    }
1796 
1797    /**
1798     * Get a double associated with the given configuration key.
1799     *
1800     * @param key The configuration key.
1801     * @param defaultValue The default value.
1802     * @return The associated double if key is found and has valid
1803     * format, default value otherwise.
1804     * @exception ClassCastException is thrown if the key maps to an
1805     * object that is not a Double.
1806     * @exception NumberFormatException is thrown if the value mapped
1807     * by the key has not a valid number format.
1808     */
1809    public Double getDouble(String key,
1810                            Double defaultValue)
1811    {
1812        Object value = get(key);
1813 
1814        if (value instanceof Double)
1815        {
1816            return (Double) value;
1817        }
1818        else if (value instanceof String)
1819        {
1820            Double d = new Double((String) value);
1821            put(key, d);
1822            return d;
1823        }
1824        else if (value == null)
1825        {
1826            if (defaults != null)
1827            {
1828                return defaults.getDouble(key, defaultValue);
1829            }
1830            else
1831            {
1832                return defaultValue;
1833            }
1834        }
1835        else
1836        {
1837            throw new ClassCastException(
1838                '\'' + key + "' doesn't map to a Double object");
1839        }
1840    }
1841 
1842    /**
1843     * Convert a standard properties class into a configuration
1844     * class.
1845     *
1846     * @param Properties properties object to convert into
1847     *                   a Configuration object.
1848     *
1849     * @return Configuration configuration created from the
1850     *                      properties object.
1851     */
1852    public static Configuration convertProperties(Properties p)
1853    {
1854        Configuration c = new Configuration();
1855    
1856        for (Enumeration e = p.keys(); e.hasMoreElements() ; ) 
1857        {
1858            String s = (String) e.nextElement();
1859            c.setProperty(s, p.getProperty(s));
1860        }
1861    
1862        return c;
1863    }
1864 
1865    /**
1866     *  <p>
1867     *  Routine intended for deprecation period only
1868     *  as we switch from using the Configuration
1869     *  class in Velocity to the Jakarta Commons
1870     *  ExtendedProperties
1871     *  </p>
1872     *  <p>
1873     *  Do not use this for general use. It will disappear
1874     * </p>
1875     *  @return ExtendedProperties containing data of Configuration
1876     *  
1877     *  @deprecated Do not use.  For deprecation assistance only.
1878     */
1879    public ExtendedProperties getExtendedProperties() 
1880    {
1881        return deprecationCrutch; 
1882    }
1883 
1884 
1885}

[all classes][org.apache.velocity.runtime.configuration]
EMMA 2.0.4015 (stable) (C) Vladimir Roubtsov