Source Code Cross Referenced for ExtendedProperties.java in  » Library » Apache-common-Collections » org » apache » commons » collections » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache common Collections » org.apache.commons.collections 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Copyright 2001-2006 The Apache Software Foundation
0003:         *
0004:         *  Licensed under the Apache License, Version 2.0 (the "License");
0005:         *  you may not use this file except in compliance with the License.
0006:         *  You may obtain a copy of the License at
0007:         *
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         *  Unless required by applicable law or agreed to in writing, software
0011:         *  distributed under the License is distributed on an "AS IS" BASIS,
0012:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         *  See the License for the specific language governing permissions and
0014:         *  limitations under the License.
0015:         */
0016:        package org.apache.commons.collections;
0017:
0018:        import java.io.File;
0019:        import java.io.FileInputStream;
0020:        import java.io.IOException;
0021:        import java.io.InputStream;
0022:        import java.io.InputStreamReader;
0023:        import java.io.LineNumberReader;
0024:        import java.io.OutputStream;
0025:        import java.io.PrintWriter;
0026:        import java.io.Reader;
0027:        import java.io.UnsupportedEncodingException;
0028:        import java.util.ArrayList;
0029:        import java.util.Enumeration;
0030:        import java.util.Hashtable;
0031:        import java.util.Iterator;
0032:        import java.util.List;
0033:        import java.util.NoSuchElementException;
0034:        import java.util.Properties;
0035:        import java.util.StringTokenizer;
0036:        import java.util.Vector;
0037:
0038:        /**
0039:         * This class extends normal Java properties by adding the possibility
0040:         * to use the same key many times concatenating the value strings
0041:         * instead of overwriting them.
0042:         * <p>
0043:         * <b>Please consider using the <code>PropertiesConfiguration</code> class in
0044:         * Commons-Configuration as soon as it is released.</b>
0045:         * <p>
0046:         * The Extended Properties syntax is explained here:
0047:         *
0048:         * <ul>
0049:         *  <li>
0050:         *   Each property has the syntax <code>key = value</code>
0051:         *  </li>
0052:         *  <li>
0053:         *   The <i>key</i> may use any character but the equal sign '='.
0054:         *  </li>
0055:         *  <li>
0056:         *   <i>value</i> may be separated on different lines if a backslash
0057:         *   is placed at the end of the line that continues below.
0058:         *  </li>
0059:         *  <li>
0060:         *   If <i>value</i> is a list of strings, each token is separated
0061:         *   by a comma ','.
0062:         *  </li>
0063:         *  <li>
0064:         *   Commas in each token are escaped placing a backslash right before
0065:         *   the comma.
0066:         *  </li>
0067:         *  <li>
0068:         *   Backslashes are escaped by using two consecutive backslashes i.e. \\
0069:         *  </li>
0070:         *  <li>
0071:         *   If a <i>key</i> is used more than once, the values are appended
0072:         *   as if they were on the same line separated with commas.
0073:         *  </li>
0074:         *  <li>
0075:         *   Blank lines and lines starting with character '#' are skipped.
0076:         *  </li>
0077:         *  <li>
0078:         *   If a property is named "include" (or whatever is defined by
0079:         *   setInclude() and getInclude() and the value of that property is
0080:         *   the full path to a file on disk, that file will be included into
0081:         *   the ConfigurationsRepository. You can also pull in files relative
0082:         *   to the parent configuration file. So if you have something
0083:         *   like the following:
0084:         *
0085:         *   include = additional.properties
0086:         *
0087:         *   Then "additional.properties" is expected to be in the same
0088:         *   directory as the parent configuration file.
0089:         * 
0090:         *   Duplicate name values will be replaced, so be careful.
0091:         *
0092:         *  </li>
0093:         * </ul>
0094:         *
0095:         * <p>Here is an example of a valid extended properties file:
0096:         *
0097:         * <p><pre>
0098:         *      # lines starting with # are comments
0099:         *
0100:         *      # This is the simplest property
0101:         *      key = value
0102:         *
0103:         *      # A long property may be separated on multiple lines
0104:         *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
0105:         *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0106:         *
0107:         *      # This is a property with many tokens
0108:         *      tokens_on_a_line = first token, second token
0109:         *
0110:         *      # This sequence generates exactly the same result
0111:         *      tokens_on_multiple_lines = first token
0112:         *      tokens_on_multiple_lines = second token
0113:         *
0114:         *      # commas may be escaped in tokens
0115:         *      commas.escaped = Hi\, what'up?
0116:         * </pre>
0117:         *
0118:         * <p><b>NOTE</b>: this class has <b>not</b> been written for
0119:         * performance nor low memory usage.  In fact, it's way slower than it
0120:         * could be and generates too much memory garbage.  But since
0121:         * performance is not an issue during intialization (and there is not
0122:         * much time to improve it), I wrote it this way.  If you don't like
0123:         * it, go ahead and tune it up!
0124:         *
0125:         * @since Commons Collections 1.0
0126:         * @version $Revision: 405927 $ $Date: 2006-05-12 23:57:03 +0100 (Fri, 12 May 2006) $
0127:         * 
0128:         * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
0129:         * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
0130:         * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
0131:         * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
0132:         * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
0133:         * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
0134:         * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
0135:         * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
0136:         * @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
0137:         * @author Janek Bogucki
0138:         * @author Mohan Kishore
0139:         * @author Stephen Colebourne
0140:         * @author Shinobu Kawai
0141:         * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
0142:         */
0143:        public class ExtendedProperties extends Hashtable {
0144:
0145:            /**
0146:             * Default configurations repository.
0147:             */
0148:            private ExtendedProperties defaults;
0149:
0150:            /**
0151:             * The file connected to this repository (holding comments and
0152:             * such).
0153:             *
0154:             * @serial
0155:             */
0156:            protected String file;
0157:
0158:            /**
0159:             * Base path of the configuration file used to create
0160:             * this ExtendedProperties object.
0161:             */
0162:            protected String basePath;
0163:
0164:            /**
0165:             * File separator.
0166:             */
0167:            protected String fileSeparator = System
0168:                    .getProperty("file.separator");
0169:
0170:            /**
0171:             * Has this configuration been intialized.
0172:             */
0173:            protected boolean isInitialized = false;
0174:
0175:            /**
0176:             * This is the name of the property that can point to other
0177:             * properties file for including other properties files.
0178:             */
0179:            protected static String include = "include";
0180:
0181:            /**
0182:             * These are the keys in the order they listed
0183:             * in the configuration file. This is useful when
0184:             * you wish to perform operations with configuration
0185:             * information in a particular order.
0186:             */
0187:            protected ArrayList keysAsListed = new ArrayList();
0188:
0189:            protected final static String START_TOKEN = "${";
0190:            protected final static String END_TOKEN = "}";
0191:
0192:            /**
0193:             * Interpolate key names to handle ${key} stuff
0194:             *
0195:             * @param base string to interpolate
0196:             * @return returns the key name with the ${key} substituted
0197:             */
0198:            protected String interpolate(String base) {
0199:                // COPIED from [configuration] 2003-12-29
0200:                return (interpolateHelper(base, null));
0201:            }
0202:
0203:            /**
0204:             * Recursive handler for multiple levels of interpolation.
0205:             *
0206:             * When called the first time, priorVariables should be null.
0207:             *
0208:             * @param base string with the ${key} variables
0209:             * @param priorVariables serves two purposes: to allow checking for
0210:             * loops, and creating a meaningful exception message should a loop
0211:             * occur.  It's 0'th element will be set to the value of base from
0212:             * the first call.  All subsequent interpolated variables are added
0213:             * afterward.
0214:             *
0215:             * @return the string with the interpolation taken care of
0216:             */
0217:            protected String interpolateHelper(String base, List priorVariables) {
0218:                // COPIED from [configuration] 2003-12-29
0219:                if (base == null) {
0220:                    return null;
0221:                }
0222:
0223:                // on the first call initialize priorVariables
0224:                // and add base as the first element
0225:                if (priorVariables == null) {
0226:                    priorVariables = new ArrayList();
0227:                    priorVariables.add(base);
0228:                }
0229:
0230:                int begin = -1;
0231:                int end = -1;
0232:                int prec = 0 - END_TOKEN.length();
0233:                String variable = null;
0234:                StringBuffer result = new StringBuffer();
0235:
0236:                // FIXME: we should probably allow the escaping of the start token
0237:                while (((begin = base.indexOf(START_TOKEN, prec
0238:                        + END_TOKEN.length())) > -1)
0239:                        && ((end = base.indexOf(END_TOKEN, begin)) > -1)) {
0240:                    result.append(base.substring(prec + END_TOKEN.length(),
0241:                            begin));
0242:                    variable = base
0243:                            .substring(begin + START_TOKEN.length(), end);
0244:
0245:                    // if we've got a loop, create a useful exception message and throw
0246:                    if (priorVariables.contains(variable)) {
0247:                        String initialBase = priorVariables.remove(0)
0248:                                .toString();
0249:                        priorVariables.add(variable);
0250:                        StringBuffer priorVariableSb = new StringBuffer();
0251:
0252:                        // create a nice trace of interpolated variables like so:
0253:                        // var1->var2->var3
0254:                        for (Iterator it = priorVariables.iterator(); it
0255:                                .hasNext();) {
0256:                            priorVariableSb.append(it.next());
0257:                            if (it.hasNext()) {
0258:                                priorVariableSb.append("->");
0259:                            }
0260:                        }
0261:
0262:                        throw new IllegalStateException(
0263:                                "infinite loop in property interpolation of "
0264:                                        + initialBase + ": "
0265:                                        + priorVariableSb.toString());
0266:                    }
0267:                    // otherwise, add this variable to the interpolation list.
0268:                    else {
0269:                        priorVariables.add(variable);
0270:                    }
0271:
0272:                    //QUESTION: getProperty or getPropertyDirect
0273:                    Object value = getProperty(variable);
0274:                    if (value != null) {
0275:                        result.append(interpolateHelper(value.toString(),
0276:                                priorVariables));
0277:
0278:                        // pop the interpolated variable off the stack
0279:                        // this maintains priorVariables correctness for
0280:                        // properties with multiple interpolations, e.g.
0281:                        // prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
0282:                        priorVariables.remove(priorVariables.size() - 1);
0283:                    } else if (defaults != null
0284:                            && defaults.getString(variable, null) != null) {
0285:                        result.append(defaults.getString(variable));
0286:                    } else {
0287:                        //variable not defined - so put it back in the value
0288:                        result.append(START_TOKEN).append(variable).append(
0289:                                END_TOKEN);
0290:                    }
0291:                    prec = end;
0292:                }
0293:                result.append(base.substring(prec + END_TOKEN.length(), base
0294:                        .length()));
0295:
0296:                return result.toString();
0297:            }
0298:
0299:            /**
0300:             * Inserts a backslash before every comma and backslash. 
0301:             */
0302:            private static String escape(String s) {
0303:                StringBuffer buf = new StringBuffer(s);
0304:                for (int i = 0; i < buf.length(); i++) {
0305:                    char c = buf.charAt(i);
0306:                    if (c == ',' || c == '\\') {
0307:                        buf.insert(i, '\\');
0308:                        i++;
0309:                    }
0310:                }
0311:                return buf.toString();
0312:            }
0313:
0314:            /**
0315:             * Removes a backslash from every pair of backslashes. 
0316:             */
0317:            private static String unescape(String s) {
0318:                StringBuffer buf = new StringBuffer(s);
0319:                for (int i = 0; i < buf.length() - 1; i++) {
0320:                    char c1 = buf.charAt(i);
0321:                    char c2 = buf.charAt(i + 1);
0322:                    if (c1 == '\\' && c2 == '\\') {
0323:                        buf.deleteCharAt(i);
0324:                    }
0325:                }
0326:                return buf.toString();
0327:            }
0328:
0329:            /**
0330:             * Counts the number of successive times 'ch' appears in the
0331:             * 'line' before the position indicated by the 'index'.
0332:             */
0333:            private static int countPreceding(String line, int index, char ch) {
0334:                int i;
0335:                for (i = index - 1; i >= 0; i--) {
0336:                    if (line.charAt(i) != ch) {
0337:                        break;
0338:                    }
0339:                }
0340:                return index - 1 - i;
0341:            }
0342:
0343:            /**
0344:             * Checks if the line ends with odd number of backslashes 
0345:             */
0346:            private static boolean endsWithSlash(String line) {
0347:                if (!line.endsWith("\\")) {
0348:                    return false;
0349:                }
0350:                return (countPreceding(line, line.length() - 1, '\\') % 2 == 0);
0351:            }
0352:
0353:            /**
0354:             * This class is used to read properties lines.  These lines do
0355:             * not terminate with new-line chars but rather when there is no
0356:             * backslash sign a the end of the line.  This is used to
0357:             * concatenate multiple lines for readability.
0358:             */
0359:            static class PropertiesReader extends LineNumberReader {
0360:                /**
0361:                 * Constructor.
0362:                 *
0363:                 * @param reader A Reader.
0364:                 */
0365:                public PropertiesReader(Reader reader) {
0366:                    super (reader);
0367:                }
0368:
0369:                /**
0370:                 * Read a property.
0371:                 *
0372:                 * @return a String property
0373:                 * @throws IOException if there is difficulty reading the source.
0374:                 */
0375:                public String readProperty() throws IOException {
0376:                    StringBuffer buffer = new StringBuffer();
0377:                    String line = readLine();
0378:                    while (line != null) {
0379:                        line = line.trim();
0380:                        if ((line.length() != 0) && (line.charAt(0) != '#')) {
0381:                            if (endsWithSlash(line)) {
0382:                                line = line.substring(0, line.length() - 1);
0383:                                buffer.append(line);
0384:                            } else {
0385:                                buffer.append(line);
0386:                                return buffer.toString(); // normal method end
0387:                            }
0388:                        }
0389:                        line = readLine();
0390:                    }
0391:                    return null; // EOF reached
0392:                }
0393:            }
0394:
0395:            /**
0396:             * This class divides into tokens a property value.  Token
0397:             * separator is "," but commas into the property value are escaped
0398:             * using the backslash in front.
0399:             */
0400:            static class PropertiesTokenizer extends StringTokenizer {
0401:                /**
0402:                 * The property delimiter used while parsing (a comma).
0403:                 */
0404:                static final String DELIMITER = ",";
0405:
0406:                /**
0407:                 * Constructor.
0408:                 *
0409:                 * @param string A String.
0410:                 */
0411:                public PropertiesTokenizer(String string) {
0412:                    super (string, DELIMITER);
0413:                }
0414:
0415:                /**
0416:                 * Check whether the object has more tokens.
0417:                 *
0418:                 * @return True if the object has more tokens.
0419:                 */
0420:                public boolean hasMoreTokens() {
0421:                    return super .hasMoreTokens();
0422:                }
0423:
0424:                /**
0425:                 * Get next token.
0426:                 *
0427:                 * @return A String.
0428:                 */
0429:                public String nextToken() {
0430:                    StringBuffer buffer = new StringBuffer();
0431:
0432:                    while (hasMoreTokens()) {
0433:                        String token = super .nextToken();
0434:                        if (endsWithSlash(token)) {
0435:                            buffer.append(token
0436:                                    .substring(0, token.length() - 1));
0437:                            buffer.append(DELIMITER);
0438:                        } else {
0439:                            buffer.append(token);
0440:                            break;
0441:                        }
0442:                    }
0443:
0444:                    return buffer.toString().trim();
0445:                }
0446:            }
0447:
0448:            /**
0449:             * Creates an empty extended properties object.
0450:             */
0451:            public ExtendedProperties() {
0452:                super ();
0453:            }
0454:
0455:            /**
0456:             * Creates and loads the extended properties from the specified file.
0457:             *
0458:             * @param file  the filename to load
0459:             * @throws IOException if a file error occurs
0460:             */
0461:            public ExtendedProperties(String file) throws IOException {
0462:                this (file, null);
0463:            }
0464:
0465:            /**
0466:             * Creates and loads the extended properties from the specified file.
0467:             *
0468:             * @param file  the filename to load
0469:             * @param defaultFile  a second filename to load default values from
0470:             * @throws IOException if a file error occurs
0471:             */
0472:            public ExtendedProperties(String file, String defaultFile)
0473:                    throws IOException {
0474:                this .file = file;
0475:
0476:                basePath = new File(file).getAbsolutePath();
0477:                basePath = basePath.substring(0, basePath
0478:                        .lastIndexOf(fileSeparator) + 1);
0479:
0480:                FileInputStream in = null;
0481:                try {
0482:                    in = new FileInputStream(file);
0483:                    this .load(in);
0484:                } finally {
0485:                    try {
0486:                        if (in != null) {
0487:                            in.close();
0488:                        }
0489:                    } catch (IOException ex) {
0490:                    }
0491:                }
0492:
0493:                if (defaultFile != null) {
0494:                    defaults = new ExtendedProperties(defaultFile);
0495:                }
0496:            }
0497:
0498:            /**
0499:             * Indicate to client code whether property
0500:             * resources have been initialized or not.
0501:             */
0502:            public boolean isInitialized() {
0503:                return isInitialized;
0504:            }
0505:
0506:            /**
0507:             * Gets the property value for including other properties files.
0508:             * By default it is "include".
0509:             *
0510:             * @return A String.
0511:             */
0512:            public String getInclude() {
0513:                return include;
0514:            }
0515:
0516:            /**
0517:             * Sets the property value for including other properties files.
0518:             * By default it is "include".
0519:             *
0520:             * @param inc A String.
0521:             */
0522:            public void setInclude(String inc) {
0523:                include = inc;
0524:            }
0525:
0526:            /**
0527:             * Load the properties from the given input stream.
0528:             *
0529:             * @param input  the InputStream to load from
0530:             * @throws IOException if an IO error occurs
0531:             */
0532:            public void load(InputStream input) throws IOException {
0533:                load(input, null);
0534:            }
0535:
0536:            /**
0537:             * Load the properties from the given input stream
0538:             * and using the specified encoding.
0539:             *
0540:             * @param input  the InputStream to load from
0541:             * @param enc  the encoding to use
0542:             * @throws IOException if an IO error occurs
0543:             */
0544:            public synchronized void load(InputStream input, String enc)
0545:                    throws IOException {
0546:                PropertiesReader reader = null;
0547:                if (enc != null) {
0548:                    try {
0549:                        reader = new PropertiesReader(new InputStreamReader(
0550:                                input, enc));
0551:
0552:                    } catch (UnsupportedEncodingException ex) {
0553:                        // Another try coming up....
0554:                    }
0555:                }
0556:
0557:                if (reader == null) {
0558:                    try {
0559:                        reader = new PropertiesReader(new InputStreamReader(
0560:                                input, "8859_1"));
0561:
0562:                    } catch (UnsupportedEncodingException ex) {
0563:                        // ISO8859-1 support is required on java platforms but....
0564:                        // If it's not supported, use the system default encoding
0565:                        reader = new PropertiesReader(new InputStreamReader(
0566:                                input));
0567:                    }
0568:                }
0569:
0570:                try {
0571:                    while (true) {
0572:                        String line = reader.readProperty();
0573:                        if (line == null) {
0574:                            return; // EOF
0575:                        }
0576:                        int equalSign = line.indexOf('=');
0577:
0578:                        if (equalSign > 0) {
0579:                            String key = line.substring(0, equalSign).trim();
0580:                            String value = line.substring(equalSign + 1).trim();
0581:
0582:                            // Configure produces lines like this ... just ignore them
0583:                            if ("".equals(value)) {
0584:                                continue;
0585:                            }
0586:
0587:                            if (getInclude() != null
0588:                                    && key.equalsIgnoreCase(getInclude())) {
0589:                                // Recursively load properties files.
0590:                                File file = null;
0591:
0592:                                if (value.startsWith(fileSeparator)) {
0593:                                    // We have an absolute path so we'll use this
0594:                                    file = new File(value);
0595:
0596:                                } else {
0597:                                    // We have a relative path, and we have two 
0598:                                    // possible forms here. If we have the "./" form
0599:                                    // then just strip that off first before continuing.
0600:                                    if (value.startsWith("." + fileSeparator)) {
0601:                                        value = value.substring(2);
0602:                                    }
0603:
0604:                                    file = new File(basePath + value);
0605:                                }
0606:
0607:                                if (file != null && file.exists()
0608:                                        && file.canRead()) {
0609:                                    load(new FileInputStream(file));
0610:                                }
0611:                            } else {
0612:                                addProperty(key, value);
0613:                            }
0614:                        }
0615:                    }
0616:                } finally {
0617:                    // Loading is initializing
0618:                    isInitialized = true;
0619:                }
0620:            }
0621:
0622:            /**
0623:             * Gets a property from the configuration.
0624:             *
0625:             * @param key property to retrieve
0626:             * @return value as object. Will return user value if exists,
0627:             *        if not then default value if exists, otherwise null
0628:             */
0629:            public Object getProperty(String key) {
0630:                // first, try to get from the 'user value' store
0631:                Object obj = this .get(key);
0632:
0633:                if (obj == null) {
0634:                    // if there isn't a value there, get it from the
0635:                    // defaults if we have them
0636:                    if (defaults != null) {
0637:                        obj = defaults.get(key);
0638:                    }
0639:                }
0640:
0641:                return obj;
0642:            }
0643:
0644:            /**
0645:             * Add a property to the configuration. If it already
0646:             * exists then the value stated here will be added
0647:             * to the configuration entry. For example, if
0648:             *
0649:             * <code>resource.loader = file</code>
0650:             *
0651:             * is already present in the configuration and you
0652:             *
0653:             * <code>addProperty("resource.loader", "classpath")</code>
0654:             *
0655:             * Then you will end up with a Vector like the
0656:             * following:
0657:             *
0658:             * <code>["file", "classpath"]</code>
0659:             *
0660:             * @param key  the key to add
0661:             * @param value  the value to add
0662:             */
0663:            public void addProperty(String key, Object value) {
0664:                if (value instanceof  String) {
0665:                    String str = (String) value;
0666:                    if (str.indexOf(PropertiesTokenizer.DELIMITER) > 0) {
0667:                        // token contains commas, so must be split apart then added
0668:                        PropertiesTokenizer tokenizer = new PropertiesTokenizer(
0669:                                str);
0670:                        while (tokenizer.hasMoreTokens()) {
0671:                            String token = tokenizer.nextToken();
0672:                            addPropertyInternal(key, unescape(token));
0673:                        }
0674:                    } else {
0675:                        // token contains no commas, so can be simply added
0676:                        addPropertyInternal(key, unescape(str));
0677:                    }
0678:                } else {
0679:                    addPropertyInternal(key, value);
0680:                }
0681:
0682:                // Adding a property connotes initialization
0683:                isInitialized = true;
0684:            }
0685:
0686:            /**
0687:             * Adds a key/value pair to the map.  This routine does
0688:             * no magic morphing.  It ensures the keylist is maintained
0689:             *
0690:             * @param key  the key to store at
0691:             * @param value  the decoded object to store
0692:             */
0693:            private void addPropertyDirect(String key, Object value) {
0694:                // safety check
0695:                if (!containsKey(key)) {
0696:                    keysAsListed.add(key);
0697:                }
0698:                put(key, value);
0699:            }
0700:
0701:            /**
0702:             * Adds a decoded property to the map w/o checking for commas - used
0703:             * internally when a property has been broken up into
0704:             * strings that could contain escaped commas to prevent
0705:             * the inadvertent vectorization.
0706:             * <p>
0707:             * Thanks to Leon Messerschmidt for this one.
0708:             *
0709:             * @param key  the key to store at
0710:             * @param value  the decoded object to store
0711:             */
0712:            private void addPropertyInternal(String key, Object value) {
0713:                Object current = this .get(key);
0714:
0715:                if (current instanceof  String) {
0716:                    // one object already in map - convert it to a vector
0717:                    List values = new Vector(2);
0718:                    values.add(current);
0719:                    values.add(value);
0720:                    put(key, values);
0721:
0722:                } else if (current instanceof  List) {
0723:                    // already a list - just add the new token
0724:                    ((List) current).add(value);
0725:
0726:                } else {
0727:                    // brand new key - store in keysAsListed to retain order
0728:                    if (!containsKey(key)) {
0729:                        keysAsListed.add(key);
0730:                    }
0731:                    put(key, value);
0732:                }
0733:            }
0734:
0735:            /**
0736:             * Set a property, this will replace any previously
0737:             * set values. Set values is implicitly a call
0738:             * to clearProperty(key), addProperty(key,value).
0739:             *
0740:             * @param key  the key to set
0741:             * @param value  the value to set
0742:             */
0743:            public void setProperty(String key, Object value) {
0744:                clearProperty(key);
0745:                addProperty(key, value);
0746:            }
0747:
0748:            /**
0749:             * Save the properties to the given output stream.
0750:             * <p>
0751:             * The stream is not closed, but it is flushed.
0752:             *
0753:             * @param output  an OutputStream, may be null
0754:             * @param header  a textual comment to act as a file header
0755:             * @throws IOException if an IO error occurs
0756:             */
0757:            public synchronized void save(OutputStream output, String header)
0758:                    throws IOException {
0759:                if (output == null) {
0760:                    return;
0761:                }
0762:                PrintWriter theWrtr = new PrintWriter(output);
0763:                if (header != null) {
0764:                    theWrtr.println(header);
0765:                }
0766:
0767:                Enumeration theKeys = keys();
0768:                while (theKeys.hasMoreElements()) {
0769:                    String key = (String) theKeys.nextElement();
0770:                    Object value = get(key);
0771:                    if (value != null) {
0772:                        if (value instanceof  String) {
0773:                            StringBuffer currentOutput = new StringBuffer();
0774:                            currentOutput.append(key);
0775:                            currentOutput.append("=");
0776:                            currentOutput.append(escape((String) value));
0777:                            theWrtr.println(currentOutput.toString());
0778:
0779:                        } else if (value instanceof  List) {
0780:                            List values = (List) value;
0781:                            for (Iterator it = values.iterator(); it.hasNext();) {
0782:                                String currentElement = (String) it.next();
0783:                                StringBuffer currentOutput = new StringBuffer();
0784:                                currentOutput.append(key);
0785:                                currentOutput.append("=");
0786:                                currentOutput.append(escape(currentElement));
0787:                                theWrtr.println(currentOutput.toString());
0788:                            }
0789:                        }
0790:                    }
0791:                    theWrtr.println();
0792:                    theWrtr.flush();
0793:                }
0794:            }
0795:
0796:            /**
0797:             * Combines an existing Hashtable with this Hashtable.
0798:             * <p>
0799:             * Warning: It will overwrite previous entries without warning.
0800:             *
0801:             * @param props  the properties to combine
0802:             */
0803:            public void combine(ExtendedProperties props) {
0804:                for (Iterator it = props.getKeys(); it.hasNext();) {
0805:                    String key = (String) it.next();
0806:                    setProperty(key, props.get(key));
0807:                }
0808:            }
0809:
0810:            /**
0811:             * Clear a property in the configuration.
0812:             *
0813:             * @param key  the property key to remove along with corresponding value
0814:             */
0815:            public void clearProperty(String key) {
0816:                if (containsKey(key)) {
0817:                    // we also need to rebuild the keysAsListed or else
0818:                    // things get *very* confusing
0819:                    for (int i = 0; i < keysAsListed.size(); i++) {
0820:                        if ((keysAsListed.get(i)).equals(key)) {
0821:                            keysAsListed.remove(i);
0822:                            break;
0823:                        }
0824:                    }
0825:                    remove(key);
0826:                }
0827:            }
0828:
0829:            /**
0830:             * Get the list of the keys contained in the configuration
0831:             * repository.
0832:             *
0833:             * @return an Iterator over the keys
0834:             */
0835:            public Iterator getKeys() {
0836:                return keysAsListed.iterator();
0837:            }
0838:
0839:            /**
0840:             * Get the list of the keys contained in the configuration
0841:             * repository that match the specified prefix.
0842:             *
0843:             * @param prefix  the prefix to match
0844:             * @return an Iterator of keys that match the prefix
0845:             */
0846:            public Iterator getKeys(String prefix) {
0847:                Iterator keys = getKeys();
0848:                ArrayList matchingKeys = new ArrayList();
0849:
0850:                while (keys.hasNext()) {
0851:                    Object key = keys.next();
0852:
0853:                    if (key instanceof  String
0854:                            && ((String) key).startsWith(prefix)) {
0855:                        matchingKeys.add(key);
0856:                    }
0857:                }
0858:                return matchingKeys.iterator();
0859:            }
0860:
0861:            /**
0862:             * Create an ExtendedProperties object that is a subset
0863:             * of this one. Take into account duplicate keys
0864:             * by using the setProperty() in ExtendedProperties.
0865:             *
0866:             * @param prefix  the prefix to get a subset for
0867:             * @return a new independent ExtendedProperties
0868:             */
0869:            public ExtendedProperties subset(String prefix) {
0870:                ExtendedProperties c = new ExtendedProperties();
0871:                Iterator keys = getKeys();
0872:                boolean validSubset = false;
0873:
0874:                while (keys.hasNext()) {
0875:                    Object key = keys.next();
0876:
0877:                    if (key instanceof  String
0878:                            && ((String) key).startsWith(prefix)) {
0879:                        if (!validSubset) {
0880:                            validSubset = true;
0881:                        }
0882:
0883:                        /*
0884:                         * Check to make sure that c.subset(prefix) doesn't
0885:                         * blow up when there is only a single property
0886:                         * with the key prefix. This is not a useful
0887:                         * subset but it is a valid subset.
0888:                         */
0889:                        String newKey = null;
0890:                        if (((String) key).length() == prefix.length()) {
0891:                            newKey = prefix;
0892:                        } else {
0893:                            newKey = ((String) key)
0894:                                    .substring(prefix.length() + 1);
0895:                        }
0896:
0897:                        /*
0898:                         *  use addPropertyDirect() - this will plug the data as 
0899:                         *  is into the Map, but will also do the right thing
0900:                         *  re key accounting
0901:                         */
0902:                        c.addPropertyDirect(newKey, get(key));
0903:                    }
0904:                }
0905:
0906:                if (validSubset) {
0907:                    return c;
0908:                } else {
0909:                    return null;
0910:                }
0911:            }
0912:
0913:            /**
0914:             * Display the configuration for debugging purposes to System.out.
0915:             */
0916:            public void display() {
0917:                Iterator i = getKeys();
0918:
0919:                while (i.hasNext()) {
0920:                    String key = (String) i.next();
0921:                    Object value = get(key);
0922:                    System.out.println(key + " => " + value);
0923:                }
0924:            }
0925:
0926:            /**
0927:             * Get a string associated with the given configuration key.
0928:             *
0929:             * @param key The configuration key.
0930:             * @return The associated string.
0931:             * @throws ClassCastException is thrown if the key maps to an
0932:             * object that is not a String.
0933:             */
0934:            public String getString(String key) {
0935:                return getString(key, null);
0936:            }
0937:
0938:            /**
0939:             * Get a string associated with the given configuration key.
0940:             *
0941:             * @param key The configuration key.
0942:             * @param defaultValue The default value.
0943:             * @return The associated string if key is found,
0944:             * default value otherwise.
0945:             * @throws ClassCastException is thrown if the key maps to an
0946:             * object that is not a String.
0947:             */
0948:            public String getString(String key, String defaultValue) {
0949:                Object value = get(key);
0950:
0951:                if (value instanceof  String) {
0952:                    return interpolate((String) value);
0953:
0954:                } else if (value == null) {
0955:                    if (defaults != null) {
0956:                        return interpolate(defaults
0957:                                .getString(key, defaultValue));
0958:                    } else {
0959:                        return interpolate(defaultValue);
0960:                    }
0961:                } else if (value instanceof  List) {
0962:                    return interpolate((String) ((List) value).get(0));
0963:                } else {
0964:                    throw new ClassCastException('\'' + key
0965:                            + "' doesn't map to a String object");
0966:                }
0967:            }
0968:
0969:            /**
0970:             * Get a list of properties associated with the given
0971:             * configuration key.
0972:             *
0973:             * @param key The configuration key.
0974:             * @return The associated properties if key is found.
0975:             * @throws ClassCastException is thrown if the key maps to an
0976:             * object that is not a String/List.
0977:             * @throws IllegalArgumentException if one of the tokens is
0978:             * malformed (does not contain an equals sign).
0979:             */
0980:            public Properties getProperties(String key) {
0981:                return getProperties(key, new Properties());
0982:            }
0983:
0984:            /**
0985:             * Get a list of properties associated with the given
0986:             * configuration key.
0987:             *
0988:             * @param key The configuration key.
0989:             * @return The associated properties if key is found.
0990:             * @throws ClassCastException is thrown if the key maps to an
0991:             * object that is not a String/List.
0992:             * @throws IllegalArgumentException if one of the tokens is
0993:             * malformed (does not contain an equals sign).
0994:             */
0995:            public Properties getProperties(String key, Properties defaults) {
0996:                /*
0997:                 * Grab an array of the tokens for this key.
0998:                 */
0999:                String[] tokens = getStringArray(key);
1000:
1001:                // Each token is of the form 'key=value'.
1002:                Properties props = new Properties(defaults);
1003:                for (int i = 0; i < tokens.length; i++) {
1004:                    String token = tokens[i];
1005:                    int equalSign = token.indexOf('=');
1006:                    if (equalSign > 0) {
1007:                        String pkey = token.substring(0, equalSign).trim();
1008:                        String pvalue = token.substring(equalSign + 1).trim();
1009:                        props.put(pkey, pvalue);
1010:                    } else {
1011:                        throw new IllegalArgumentException('\'' + token
1012:                                + "' does not contain " + "an equals sign");
1013:                    }
1014:                }
1015:                return props;
1016:            }
1017:
1018:            /**
1019:             * Get an array of strings associated with the given configuration
1020:             * key.
1021:             *
1022:             * @param key The configuration key.
1023:             * @return The associated string array if key is found.
1024:             * @throws ClassCastException is thrown if the key maps to an
1025:             * object that is not a String/List.
1026:             */
1027:            public String[] getStringArray(String key) {
1028:                Object value = get(key);
1029:
1030:                List values;
1031:                if (value instanceof  String) {
1032:                    values = new Vector(1);
1033:                    values.add(value);
1034:
1035:                } else if (value instanceof  List) {
1036:                    values = (List) value;
1037:
1038:                } else if (value == null) {
1039:                    if (defaults != null) {
1040:                        return defaults.getStringArray(key);
1041:                    } else {
1042:                        return new String[0];
1043:                    }
1044:                } else {
1045:                    throw new ClassCastException('\'' + key
1046:                            + "' doesn't map to a String/List object");
1047:                }
1048:
1049:                String[] tokens = new String[values.size()];
1050:                for (int i = 0; i < tokens.length; i++) {
1051:                    tokens[i] = (String) values.get(i);
1052:                }
1053:
1054:                return tokens;
1055:            }
1056:
1057:            /**
1058:             * Get a Vector of strings associated with the given configuration
1059:             * key.
1060:             *
1061:             * @param key The configuration key.
1062:             * @return The associated Vector.
1063:             * @throws ClassCastException is thrown if the key maps to an
1064:             * object that is not a Vector.
1065:             */
1066:            public Vector getVector(String key) {
1067:                return getVector(key, null);
1068:            }
1069:
1070:            /**
1071:             * Get a Vector of strings associated with the given configuration key.
1072:             * <p>
1073:             * The list is a copy of the internal data of this object, and as
1074:             * such you may alter it freely.
1075:             *
1076:             * @param key The configuration key.
1077:             * @param defaultValue The default value.
1078:             * @return The associated Vector.
1079:             * @throws ClassCastException is thrown if the key maps to an
1080:             * object that is not a Vector.
1081:             */
1082:            public Vector getVector(String key, Vector defaultValue) {
1083:                Object value = get(key);
1084:
1085:                if (value instanceof  List) {
1086:                    return new Vector((List) value);
1087:
1088:                } else if (value instanceof  String) {
1089:                    Vector values = new Vector(1);
1090:                    values.add(value);
1091:                    put(key, values);
1092:                    return values;
1093:
1094:                } else if (value == null) {
1095:                    if (defaults != null) {
1096:                        return defaults.getVector(key, defaultValue);
1097:                    } else {
1098:                        return ((defaultValue == null) ? new Vector()
1099:                                : defaultValue);
1100:                    }
1101:                } else {
1102:                    throw new ClassCastException('\'' + key
1103:                            + "' doesn't map to a Vector object");
1104:                }
1105:            }
1106:
1107:            /**
1108:             * Get a List of strings associated with the given configuration key.
1109:             * <p>
1110:             * The list is a copy of the internal data of this object, and as
1111:             * such you may alter it freely.
1112:             *
1113:             * @param key The configuration key.
1114:             * @return The associated List object.
1115:             * @throws ClassCastException is thrown if the key maps to an
1116:             * object that is not a List.
1117:             * @since Commons Collections 3.2
1118:             */
1119:            public List getList(String key) {
1120:                return getList(key, null);
1121:            }
1122:
1123:            /**
1124:             * Get a List of strings associated with the given configuration key.
1125:             * <p>
1126:             * The list is a copy of the internal data of this object, and as
1127:             * such you may alter it freely.
1128:             *
1129:             * @param key The configuration key.
1130:             * @param defaultValue The default value.
1131:             * @return The associated List.
1132:             * @throws ClassCastException is thrown if the key maps to an
1133:             * object that is not a List.
1134:             * @since Commons Collections 3.2
1135:             */
1136:            public List getList(String key, List defaultValue) {
1137:                Object value = get(key);
1138:
1139:                if (value instanceof  List) {
1140:                    return new ArrayList((List) value);
1141:
1142:                } else if (value instanceof  String) {
1143:                    List values = new ArrayList(1);
1144:                    values.add(value);
1145:                    put(key, values);
1146:                    return values;
1147:
1148:                } else if (value == null) {
1149:                    if (defaults != null) {
1150:                        return defaults.getList(key, defaultValue);
1151:                    } else {
1152:                        return ((defaultValue == null) ? new ArrayList()
1153:                                : defaultValue);
1154:                    }
1155:                } else {
1156:                    throw new ClassCastException('\'' + key
1157:                            + "' doesn't map to a List object");
1158:                }
1159:            }
1160:
1161:            /**
1162:             * Get a boolean associated with the given configuration key.
1163:             *
1164:             * @param key The configuration key.
1165:             * @return The associated boolean.
1166:             * @throws NoSuchElementException is thrown if the key doesn't
1167:             * map to an existing object.
1168:             * @throws ClassCastException is thrown if the key maps to an
1169:             * object that is not a Boolean.
1170:             */
1171:            public boolean getBoolean(String key) {
1172:                Boolean b = getBoolean(key, null);
1173:                if (b != null) {
1174:                    return b.booleanValue();
1175:                } else {
1176:                    throw new NoSuchElementException('\'' + key
1177:                            + "' doesn't map to an existing object");
1178:                }
1179:            }
1180:
1181:            /**
1182:             * Get a boolean associated with the given configuration key.
1183:             *
1184:             * @param key The configuration key.
1185:             * @param defaultValue The default value.
1186:             * @return The associated boolean.
1187:             * @throws ClassCastException is thrown if the key maps to an
1188:             * object that is not a Boolean.
1189:             */
1190:            public boolean getBoolean(String key, boolean defaultValue) {
1191:                return getBoolean(key, new Boolean(defaultValue))
1192:                        .booleanValue();
1193:            }
1194:
1195:            /**
1196:             * Get a boolean associated with the given configuration key.
1197:             *
1198:             * @param key The configuration key.
1199:             * @param defaultValue The default value.
1200:             * @return The associated boolean if key is found and has valid
1201:             * format, default value otherwise.
1202:             * @throws ClassCastException is thrown if the key maps to an
1203:             * object that is not a Boolean.
1204:             */
1205:            public Boolean getBoolean(String key, Boolean defaultValue) {
1206:
1207:                Object value = get(key);
1208:
1209:                if (value instanceof  Boolean) {
1210:                    return (Boolean) value;
1211:
1212:                } else if (value instanceof  String) {
1213:                    String s = testBoolean((String) value);
1214:                    Boolean b = new Boolean(s);
1215:                    put(key, b);
1216:                    return b;
1217:
1218:                } else if (value == null) {
1219:                    if (defaults != null) {
1220:                        return defaults.getBoolean(key, defaultValue);
1221:                    } else {
1222:                        return defaultValue;
1223:                    }
1224:                } else {
1225:                    throw new ClassCastException('\'' + key
1226:                            + "' doesn't map to a Boolean object");
1227:                }
1228:            }
1229:
1230:            /**
1231:             * Test whether the string represent by value maps to a boolean
1232:             * value or not. We will allow <code>true</code>, <code>on</code>,
1233:             * and <code>yes</code> for a <code>true</code> boolean value, and
1234:             * <code>false</code>, <code>off</code>, and <code>no</code> for
1235:             * <code>false</code> boolean values.  Case of value to test for
1236:             * boolean status is ignored.
1237:             *
1238:             * @param value  the value to test for boolean state
1239:             * @return <code>true</code> or <code>false</code> if the supplied
1240:             * text maps to a boolean value, or <code>null</code> otherwise.
1241:             */
1242:            public String testBoolean(String value) {
1243:                String s = value.toLowerCase();
1244:
1245:                if (s.equals("true") || s.equals("on") || s.equals("yes")) {
1246:                    return "true";
1247:                } else if (s.equals("false") || s.equals("off")
1248:                        || s.equals("no")) {
1249:                    return "false";
1250:                } else {
1251:                    return null;
1252:                }
1253:            }
1254:
1255:            /**
1256:             * Get a byte associated with the given configuration key.
1257:             *
1258:             * @param key The configuration key.
1259:             * @return The associated byte.
1260:             * @throws NoSuchElementException is thrown if the key doesn't
1261:             * map to an existing object.
1262:             * @throws ClassCastException is thrown if the key maps to an
1263:             * object that is not a Byte.
1264:             * @throws NumberFormatException is thrown if the value mapped
1265:             * by the key has not a valid number format.
1266:             */
1267:            public byte getByte(String key) {
1268:                Byte b = getByte(key, null);
1269:                if (b != null) {
1270:                    return b.byteValue();
1271:                } else {
1272:                    throw new NoSuchElementException('\'' + key
1273:                            + " doesn't map to an existing object");
1274:                }
1275:            }
1276:
1277:            /**
1278:             * Get a byte associated with the given configuration key.
1279:             *
1280:             * @param key The configuration key.
1281:             * @param defaultValue The default value.
1282:             * @return The associated byte.
1283:             * @throws ClassCastException is thrown if the key maps to an
1284:             * object that is not a Byte.
1285:             * @throws NumberFormatException is thrown if the value mapped
1286:             * by the key has not a valid number format.
1287:             */
1288:            public byte getByte(String key, byte defaultValue) {
1289:                return getByte(key, new Byte(defaultValue)).byteValue();
1290:            }
1291:
1292:            /**
1293:             * Get a byte associated with the given configuration key.
1294:             *
1295:             * @param key The configuration key.
1296:             * @param defaultValue The default value.
1297:             * @return The associated byte if key is found and has valid
1298:             * format, default value otherwise.
1299:             * @throws ClassCastException is thrown if the key maps to an
1300:             * object that is not a Byte.
1301:             * @throws NumberFormatException is thrown if the value mapped
1302:             * by the key has not a valid number format.
1303:             */
1304:            public Byte getByte(String key, Byte defaultValue) {
1305:                Object value = get(key);
1306:
1307:                if (value instanceof  Byte) {
1308:                    return (Byte) value;
1309:
1310:                } else if (value instanceof  String) {
1311:                    Byte b = new Byte((String) value);
1312:                    put(key, b);
1313:                    return b;
1314:
1315:                } else if (value == null) {
1316:                    if (defaults != null) {
1317:                        return defaults.getByte(key, defaultValue);
1318:                    } else {
1319:                        return defaultValue;
1320:                    }
1321:                } else {
1322:                    throw new ClassCastException('\'' + key
1323:                            + "' doesn't map to a Byte object");
1324:                }
1325:            }
1326:
1327:            /**
1328:             * Get a short associated with the given configuration key.
1329:             *
1330:             * @param key The configuration key.
1331:             * @return The associated short.
1332:             * @throws NoSuchElementException is thrown if the key doesn't
1333:             * map to an existing object.
1334:             * @throws ClassCastException is thrown if the key maps to an
1335:             * object that is not a Short.
1336:             * @throws NumberFormatException is thrown if the value mapped
1337:             * by the key has not a valid number format.
1338:             */
1339:            public short getShort(String key) {
1340:                Short s = getShort(key, null);
1341:                if (s != null) {
1342:                    return s.shortValue();
1343:                } else {
1344:                    throw new NoSuchElementException('\'' + key
1345:                            + "' doesn't map to an existing object");
1346:                }
1347:            }
1348:
1349:            /**
1350:             * Get a short associated with the given configuration key.
1351:             *
1352:             * @param key The configuration key.
1353:             * @param defaultValue The default value.
1354:             * @return The associated short.
1355:             * @throws ClassCastException is thrown if the key maps to an
1356:             * object that is not a Short.
1357:             * @throws NumberFormatException is thrown if the value mapped
1358:             * by the key has not a valid number format.
1359:             */
1360:            public short getShort(String key, short defaultValue) {
1361:                return getShort(key, new Short(defaultValue)).shortValue();
1362:            }
1363:
1364:            /**
1365:             * Get a short associated with the given configuration key.
1366:             *
1367:             * @param key The configuration key.
1368:             * @param defaultValue The default value.
1369:             * @return The associated short if key is found and has valid
1370:             * format, default value otherwise.
1371:             * @throws ClassCastException is thrown if the key maps to an
1372:             * object that is not a Short.
1373:             * @throws NumberFormatException is thrown if the value mapped
1374:             * by the key has not a valid number format.
1375:             */
1376:            public Short getShort(String key, Short defaultValue) {
1377:                Object value = get(key);
1378:
1379:                if (value instanceof  Short) {
1380:                    return (Short) value;
1381:
1382:                } else if (value instanceof  String) {
1383:                    Short s = new Short((String) value);
1384:                    put(key, s);
1385:                    return s;
1386:
1387:                } else if (value == null) {
1388:                    if (defaults != null) {
1389:                        return defaults.getShort(key, defaultValue);
1390:                    } else {
1391:                        return defaultValue;
1392:                    }
1393:                } else {
1394:                    throw new ClassCastException('\'' + key
1395:                            + "' doesn't map to a Short object");
1396:                }
1397:            }
1398:
1399:            /**
1400:             * The purpose of this method is to get the configuration resource
1401:             * with the given name as an integer.
1402:             *
1403:             * @param name The resource name.
1404:             * @return The value of the resource as an integer.
1405:             */
1406:            public int getInt(String name) {
1407:                return getInteger(name);
1408:            }
1409:
1410:            /**
1411:             * The purpose of this method is to get the configuration resource
1412:             * with the given name as an integer, or a default value.
1413:             *
1414:             * @param name The resource name
1415:             * @param def The default value of the resource.
1416:             * @return The value of the resource as an integer.
1417:             */
1418:            public int getInt(String name, int def) {
1419:                return getInteger(name, def);
1420:            }
1421:
1422:            /**
1423:             * Get a int associated with the given configuration key.
1424:             *
1425:             * @param key The configuration key.
1426:             * @return The associated int.
1427:             * @throws NoSuchElementException is thrown if the key doesn't
1428:             * map to an existing object.
1429:             * @throws ClassCastException is thrown if the key maps to an
1430:             * object that is not a Integer.
1431:             * @throws NumberFormatException is thrown if the value mapped
1432:             * by the key has not a valid number format.
1433:             */
1434:            public int getInteger(String key) {
1435:                Integer i = getInteger(key, null);
1436:                if (i != null) {
1437:                    return i.intValue();
1438:                } else {
1439:                    throw new NoSuchElementException('\'' + key
1440:                            + "' doesn't map to an existing object");
1441:                }
1442:            }
1443:
1444:            /**
1445:             * Get a int associated with the given configuration key.
1446:             *
1447:             * @param key The configuration key.
1448:             * @param defaultValue The default value.
1449:             * @return The associated int.
1450:             * @throws ClassCastException is thrown if the key maps to an
1451:             * object that is not a Integer.
1452:             * @throws NumberFormatException is thrown if the value mapped
1453:             * by the key has not a valid number format.
1454:             */
1455:            public int getInteger(String key, int defaultValue) {
1456:                Integer i = getInteger(key, null);
1457:
1458:                if (i == null) {
1459:                    return defaultValue;
1460:                }
1461:                return i.intValue();
1462:            }
1463:
1464:            /**
1465:             * Get a int associated with the given configuration key.
1466:             *
1467:             * @param key The configuration key.
1468:             * @param defaultValue The default value.
1469:             * @return The associated int if key is found and has valid
1470:             * format, default value otherwise.
1471:             * @throws ClassCastException is thrown if the key maps to an
1472:             * object that is not a Integer.
1473:             * @throws NumberFormatException is thrown if the value mapped
1474:             * by the key has not a valid number format.
1475:             */
1476:            public Integer getInteger(String key, Integer defaultValue) {
1477:                Object value = get(key);
1478:
1479:                if (value instanceof  Integer) {
1480:                    return (Integer) value;
1481:
1482:                } else if (value instanceof  String) {
1483:                    Integer i = new Integer((String) value);
1484:                    put(key, i);
1485:                    return i;
1486:
1487:                } else if (value == null) {
1488:                    if (defaults != null) {
1489:                        return defaults.getInteger(key, defaultValue);
1490:                    } else {
1491:                        return defaultValue;
1492:                    }
1493:                } else {
1494:                    throw new ClassCastException('\'' + key
1495:                            + "' doesn't map to a Integer object");
1496:                }
1497:            }
1498:
1499:            /**
1500:             * Get a long associated with the given configuration key.
1501:             *
1502:             * @param key The configuration key.
1503:             * @return The associated long.
1504:             * @throws NoSuchElementException is thrown if the key doesn't
1505:             * map to an existing object.
1506:             * @throws ClassCastException is thrown if the key maps to an
1507:             * object that is not a Long.
1508:             * @throws NumberFormatException is thrown if the value mapped
1509:             * by the key has not a valid number format.
1510:             */
1511:            public long getLong(String key) {
1512:                Long l = getLong(key, null);
1513:                if (l != null) {
1514:                    return l.longValue();
1515:                } else {
1516:                    throw new NoSuchElementException('\'' + key
1517:                            + "' doesn't map to an existing object");
1518:                }
1519:            }
1520:
1521:            /**
1522:             * Get a long associated with the given configuration key.
1523:             *
1524:             * @param key The configuration key.
1525:             * @param defaultValue The default value.
1526:             * @return The associated long.
1527:             * @throws ClassCastException is thrown if the key maps to an
1528:             * object that is not a Long.
1529:             * @throws NumberFormatException is thrown if the value mapped
1530:             * by the key has not a valid number format.
1531:             */
1532:            public long getLong(String key, long defaultValue) {
1533:                return getLong(key, new Long(defaultValue)).longValue();
1534:            }
1535:
1536:            /**
1537:             * Get a long associated with the given configuration key.
1538:             *
1539:             * @param key The configuration key.
1540:             * @param defaultValue The default value.
1541:             * @return The associated long if key is found and has valid
1542:             * format, default value otherwise.
1543:             * @throws ClassCastException is thrown if the key maps to an
1544:             * object that is not a Long.
1545:             * @throws NumberFormatException is thrown if the value mapped
1546:             * by the key has not a valid number format.
1547:             */
1548:            public Long getLong(String key, Long defaultValue) {
1549:                Object value = get(key);
1550:
1551:                if (value instanceof  Long) {
1552:                    return (Long) value;
1553:
1554:                } else if (value instanceof  String) {
1555:                    Long l = new Long((String) value);
1556:                    put(key, l);
1557:                    return l;
1558:
1559:                } else if (value == null) {
1560:                    if (defaults != null) {
1561:                        return defaults.getLong(key, defaultValue);
1562:                    } else {
1563:                        return defaultValue;
1564:                    }
1565:                } else {
1566:                    throw new ClassCastException('\'' + key
1567:                            + "' doesn't map to a Long object");
1568:                }
1569:            }
1570:
1571:            /**
1572:             * Get a float associated with the given configuration key.
1573:             *
1574:             * @param key The configuration key.
1575:             * @return The associated float.
1576:             * @throws NoSuchElementException is thrown if the key doesn't
1577:             * map to an existing object.
1578:             * @throws ClassCastException is thrown if the key maps to an
1579:             * object that is not a Float.
1580:             * @throws NumberFormatException is thrown if the value mapped
1581:             * by the key has not a valid number format.
1582:             */
1583:            public float getFloat(String key) {
1584:                Float f = getFloat(key, null);
1585:                if (f != null) {
1586:                    return f.floatValue();
1587:                } else {
1588:                    throw new NoSuchElementException('\'' + key
1589:                            + "' doesn't map to an existing object");
1590:                }
1591:            }
1592:
1593:            /**
1594:             * Get a float associated with the given configuration key.
1595:             *
1596:             * @param key The configuration key.
1597:             * @param defaultValue The default value.
1598:             * @return The associated float.
1599:             * @throws ClassCastException is thrown if the key maps to an
1600:             * object that is not a Float.
1601:             * @throws NumberFormatException is thrown if the value mapped
1602:             * by the key has not a valid number format.
1603:             */
1604:            public float getFloat(String key, float defaultValue) {
1605:                return getFloat(key, new Float(defaultValue)).floatValue();
1606:            }
1607:
1608:            /**
1609:             * Get a float associated with the given configuration key.
1610:             *
1611:             * @param key The configuration key.
1612:             * @param defaultValue The default value.
1613:             * @return The associated float if key is found and has valid
1614:             * format, default value otherwise.
1615:             * @throws ClassCastException is thrown if the key maps to an
1616:             * object that is not a Float.
1617:             * @throws NumberFormatException is thrown if the value mapped
1618:             * by the key has not a valid number format.
1619:             */
1620:            public Float getFloat(String key, Float defaultValue) {
1621:                Object value = get(key);
1622:
1623:                if (value instanceof  Float) {
1624:                    return (Float) value;
1625:
1626:                } else if (value instanceof  String) {
1627:                    Float f = new Float((String) value);
1628:                    put(key, f);
1629:                    return f;
1630:
1631:                } else if (value == null) {
1632:                    if (defaults != null) {
1633:                        return defaults.getFloat(key, defaultValue);
1634:                    } else {
1635:                        return defaultValue;
1636:                    }
1637:                } else {
1638:                    throw new ClassCastException('\'' + key
1639:                            + "' doesn't map to a Float object");
1640:                }
1641:            }
1642:
1643:            /**
1644:             * Get a double associated with the given configuration key.
1645:             *
1646:             * @param key The configuration key.
1647:             * @return The associated double.
1648:             * @throws NoSuchElementException is thrown if the key doesn't
1649:             * map to an existing object.
1650:             * @throws ClassCastException is thrown if the key maps to an
1651:             * object that is not a Double.
1652:             * @throws NumberFormatException is thrown if the value mapped
1653:             * by the key has not a valid number format.
1654:             */
1655:            public double getDouble(String key) {
1656:                Double d = getDouble(key, null);
1657:                if (d != null) {
1658:                    return d.doubleValue();
1659:                } else {
1660:                    throw new NoSuchElementException('\'' + key
1661:                            + "' doesn't map to an existing object");
1662:                }
1663:            }
1664:
1665:            /**
1666:             * Get a double associated with the given configuration key.
1667:             *
1668:             * @param key The configuration key.
1669:             * @param defaultValue The default value.
1670:             * @return The associated double.
1671:             * @throws ClassCastException is thrown if the key maps to an
1672:             * object that is not a Double.
1673:             * @throws NumberFormatException is thrown if the value mapped
1674:             * by the key has not a valid number format.
1675:             */
1676:            public double getDouble(String key, double defaultValue) {
1677:                return getDouble(key, new Double(defaultValue)).doubleValue();
1678:            }
1679:
1680:            /**
1681:             * Get a double associated with the given configuration key.
1682:             *
1683:             * @param key The configuration key.
1684:             * @param defaultValue The default value.
1685:             * @return The associated double if key is found and has valid
1686:             * format, default value otherwise.
1687:             * @throws ClassCastException is thrown if the key maps to an
1688:             * object that is not a Double.
1689:             * @throws NumberFormatException is thrown if the value mapped
1690:             * by the key has not a valid number format.
1691:             */
1692:            public Double getDouble(String key, Double defaultValue) {
1693:                Object value = get(key);
1694:
1695:                if (value instanceof  Double) {
1696:                    return (Double) value;
1697:
1698:                } else if (value instanceof  String) {
1699:                    Double d = new Double((String) value);
1700:                    put(key, d);
1701:                    return d;
1702:
1703:                } else if (value == null) {
1704:                    if (defaults != null) {
1705:                        return defaults.getDouble(key, defaultValue);
1706:                    } else {
1707:                        return defaultValue;
1708:                    }
1709:                } else {
1710:                    throw new ClassCastException('\'' + key
1711:                            + "' doesn't map to a Double object");
1712:                }
1713:            }
1714:
1715:            /**
1716:             * Convert a standard properties class into a configuration class.
1717:             * <p>
1718:             * NOTE: From Commons Collections 3.2 this method will pick up
1719:             * any default parent Properties of the specified input object.
1720:             *
1721:             * @param props  the properties object to convert
1722:             * @return new ExtendedProperties created from props
1723:             */
1724:            public static ExtendedProperties convertProperties(Properties props) {
1725:                ExtendedProperties c = new ExtendedProperties();
1726:
1727:                for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
1728:                    String s = (String) e.nextElement();
1729:                    c.setProperty(s, props.getProperty(s));
1730:                }
1731:
1732:                return c;
1733:            }
1734:
1735:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.