1 | package 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 | |
59 | import java.io.IOException; |
60 | import java.io.File; |
61 | import java.io.FileInputStream; |
62 | import java.io.InputStream; |
63 | import java.io.InputStreamReader; |
64 | import java.io.LineNumberReader; |
65 | import java.io.OutputStream; |
66 | import java.io.PrintWriter; |
67 | import java.io.Reader; |
68 | |
69 | import java.util.ArrayList; |
70 | import java.util.Enumeration; |
71 | import java.util.Hashtable; |
72 | import java.util.Iterator; |
73 | import java.util.NoSuchElementException; |
74 | import java.util.Properties; |
75 | import java.util.StringTokenizer; |
76 | import java.util.Vector; |
77 | |
78 | import 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 | */ |
174 | public 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 | } |