Source Code Cross Referenced for ConfigurationKey.java in  » Library » Apache-commons-configuration-1.4-src » org » apache » commons » configuration » 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 commons configuration 1.4 src » org.apache.commons.configuration 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        package org.apache.commons.configuration;
019:
020:        import java.io.Serializable;
021:        import java.util.Iterator;
022:        import java.util.NoSuchElementException;
023:
024:        /**
025:         * <p>A simple class that supports creation of and iteration on complex
026:         * configuration keys.</p>
027:         *
028:         * <p>For key creation the class works similar to a StringBuffer: There are
029:         * several <code>appendXXXX()</code> methods with which single parts
030:         * of a key can be constructed. All these methods return a reference to the
031:         * actual object so they can be written in a chain. When using this methods
032:         * the exact syntax for keys need not be known.</p>
033:         *
034:         * <p>This class also defines a specialized iterator for configuration keys.
035:         * With such an iterator a key can be tokenized into its single parts. For
036:         * each part it can be checked whether it has an associated index.</p>
037:         *
038:         * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
039:         * @version $Id: ConfigurationKey.java 439648 2006-09-02 20:42:10Z oheger $
040:         */
041:        public class ConfigurationKey implements  Serializable {
042:            /** Constant for a property delimiter.*/
043:            public static final char PROPERTY_DELIMITER = '.';
044:
045:            /** Constant for an escaped delimiter. */
046:            public static final String ESCAPED_DELIMITER = String
047:                    .valueOf(PROPERTY_DELIMITER)
048:                    + String.valueOf(PROPERTY_DELIMITER);
049:
050:            /** Constant for an attribute start marker.*/
051:            private static final String ATTRIBUTE_START = "[@";
052:
053:            /** Constant for an attribute end marker.*/
054:            private static final String ATTRIBUTE_END = "]";
055:
056:            /** Constant for an index start marker.*/
057:            private static final char INDEX_START = '(';
058:
059:            /** Constant for an index end marker.*/
060:            private static final char INDEX_END = ')';
061:
062:            /** Constant for the initial StringBuffer size.*/
063:            private static final int INITIAL_SIZE = 32;
064:
065:            /**
066:             * The serial version ID.
067:             */
068:            private static final long serialVersionUID = -4299732083605277656L;
069:
070:            /** Holds a buffer with the so far created key.*/
071:            private StringBuffer keyBuffer;
072:
073:            /**
074:             * Creates a new, empty instance of <code>ConfigurationKey</code>.
075:             */
076:            public ConfigurationKey() {
077:                keyBuffer = new StringBuffer(INITIAL_SIZE);
078:            }
079:
080:            /**
081:             * Creates a new instance of <code>ConfigurationKey</code> and
082:             * initializes it with the given key.
083:             *
084:             * @param key the key as a string
085:             */
086:            public ConfigurationKey(String key) {
087:                keyBuffer = new StringBuffer(key);
088:                removeTrailingDelimiter();
089:            }
090:
091:            /**
092:             * Appends the name of a property to this key. If necessary, a
093:             * property delimiter will be added.
094:             *
095:             * @param property the name of the property to be added
096:             * @return a reference to this object
097:             */
098:            public ConfigurationKey append(String property) {
099:                if (keyBuffer.length() > 0 && !hasDelimiter()
100:                        && !isAttributeKey(property)) {
101:                    keyBuffer.append(PROPERTY_DELIMITER);
102:                }
103:
104:                keyBuffer.append(property);
105:                removeTrailingDelimiter();
106:                return this ;
107:            }
108:
109:            /**
110:             * Appends an index to this configuration key.
111:             *
112:             * @param index the index to be appended
113:             * @return a reference to this object
114:             */
115:            public ConfigurationKey appendIndex(int index) {
116:                keyBuffer.append(INDEX_START).append(index);
117:                keyBuffer.append(INDEX_END);
118:                return this ;
119:            }
120:
121:            /**
122:             * Appends an attribute to this configuration key.
123:             *
124:             * @param attr the name of the attribute to be appended
125:             * @return a reference to this object
126:             */
127:            public ConfigurationKey appendAttribute(String attr) {
128:                keyBuffer.append(constructAttributeKey(attr));
129:                return this ;
130:            }
131:
132:            /**
133:             * Checks if this key is an attribute key.
134:             *
135:             * @return a flag if this key is an attribute key
136:             */
137:            public boolean isAttributeKey() {
138:                return isAttributeKey(keyBuffer.toString());
139:            }
140:
141:            /**
142:             * Checks if the passed in key is an attribute key. Such attribute keys
143:             * start and end with certain marker strings. In some cases they must be
144:             * treated slightly different.
145:             *
146:             * @param key the key (part) to be checked
147:             * @return a flag if this key is an attribute key
148:             */
149:            public static boolean isAttributeKey(String key) {
150:                return key != null && key.startsWith(ATTRIBUTE_START)
151:                        && key.endsWith(ATTRIBUTE_END);
152:            }
153:
154:            /**
155:             * Decorates the given key so that it represents an attribute. Adds
156:             * special start and end markers.
157:             *
158:             * @param key the key to be decorated
159:             * @return the decorated attribute key
160:             */
161:            public static String constructAttributeKey(String key) {
162:                StringBuffer buf = new StringBuffer();
163:                buf.append(ATTRIBUTE_START).append(key).append(ATTRIBUTE_END);
164:                return buf.toString();
165:            }
166:
167:            /**
168:             * Extracts the name of the attribute from the given attribute key.
169:             * This method removes the attribute markers - if any - from the
170:             * specified key.
171:             *
172:             * @param key the attribute key
173:             * @return the name of the corresponding attribute
174:             */
175:            public static String attributeName(String key) {
176:                return isAttributeKey(key) ? removeAttributeMarkers(key) : key;
177:            }
178:
179:            /**
180:             * Helper method for removing attribute markers from a key.
181:             *
182:             * @param key the key
183:             * @return the key with removed attribute markers
184:             */
185:            static String removeAttributeMarkers(String key) {
186:                return key.substring(ATTRIBUTE_START.length(), key.length()
187:                        - ATTRIBUTE_END.length());
188:            }
189:
190:            /**
191:             * Helper method that checks if the actual buffer ends with a property
192:             * delimiter.
193:             *
194:             * @return a flag if there is a trailing delimiter
195:             */
196:            private boolean hasDelimiter() {
197:                int count = 0;
198:                for (int idx = keyBuffer.length() - 1; idx >= 0
199:                        && keyBuffer.charAt(idx) == PROPERTY_DELIMITER; idx--) {
200:                    count++;
201:                }
202:                return count % 2 == 1;
203:            }
204:
205:            /**
206:             * Removes a trailing delimiter if there is any.
207:             */
208:            private void removeTrailingDelimiter() {
209:                while (hasDelimiter()) {
210:                    keyBuffer.deleteCharAt(keyBuffer.length() - 1);
211:                }
212:            }
213:
214:            /**
215:             * Returns a string representation of this object. This is the
216:             * configuration key as a plain string.
217:             *
218:             * @return a string for this object
219:             */
220:            public String toString() {
221:                return keyBuffer.toString();
222:            }
223:
224:            /**
225:             * Returns an iterator for iterating over the single components of
226:             * this configuration key.
227:             *
228:             * @return an iterator for this key
229:             */
230:            public KeyIterator iterator() {
231:                return new KeyIterator();
232:            }
233:
234:            /**
235:             * Returns the actual length of this configuration key.
236:             *
237:             * @return the length of this key
238:             */
239:            public int length() {
240:                return keyBuffer.length();
241:            }
242:
243:            /**
244:             * Sets the new length of this configuration key. With this method it is
245:             * possible to truncate the key, e.g. to return to a state prior calling
246:             * some <code>append()</code> methods. The semantic is the same as
247:             * the <code>setLength()</code> method of <code>StringBuffer</code>.
248:             *
249:             * @param len the new length of the key
250:             */
251:            public void setLength(int len) {
252:                keyBuffer.setLength(len);
253:            }
254:
255:            /**
256:             * Checks if two <code>ConfigurationKey</code> objects are equal. The
257:             * method can be called with strings or other objects, too.
258:             *
259:             * @param c the object to compare
260:             * @return a flag if both objects are equal
261:             */
262:            public boolean equals(Object c) {
263:                if (c == null) {
264:                    return false;
265:                }
266:
267:                return keyBuffer.toString().equals(c.toString());
268:            }
269:
270:            /**
271:             * Returns the hash code for this object.
272:             *
273:             * @return the hash code
274:             */
275:            public int hashCode() {
276:                return String.valueOf(keyBuffer).hashCode();
277:            }
278:
279:            /**
280:             * Returns a configuration key object that is initialized with the part
281:             * of the key that is common to this key and the passed in key.
282:             *
283:             * @param other the other key
284:             * @return a key object with the common key part
285:             */
286:            public ConfigurationKey commonKey(ConfigurationKey other) {
287:                if (other == null) {
288:                    throw new IllegalArgumentException(
289:                            "Other key must no be null!");
290:                }
291:
292:                ConfigurationKey result = new ConfigurationKey();
293:                KeyIterator it1 = iterator();
294:                KeyIterator it2 = other.iterator();
295:
296:                while (it1.hasNext() && it2.hasNext() && partsEqual(it1, it2)) {
297:                    if (it1.isAttribute()) {
298:                        result.appendAttribute(it1.currentKey());
299:                    } else {
300:                        result.append(it1.currentKey());
301:                        if (it1.hasIndex) {
302:                            result.appendIndex(it1.getIndex());
303:                        }
304:                    }
305:                }
306:
307:                return result;
308:            }
309:
310:            /**
311:             * Returns the &quot;difference key&quot; to a given key. This value
312:             * is the part of the passed in key that differs from this key. There is
313:             * the following relation:
314:             * <code>other = key.commonKey(other) + key.differenceKey(other)</code>
315:             * for an arbitrary configuration key <code>key</code>.
316:             *
317:             * @param other the key for which the difference is to be calculated
318:             * @return the difference key
319:             */
320:            public ConfigurationKey differenceKey(ConfigurationKey other) {
321:                ConfigurationKey common = commonKey(other);
322:                ConfigurationKey result = new ConfigurationKey();
323:
324:                if (common.length() < other.length()) {
325:                    String k = other.toString().substring(common.length());
326:                    // skip trailing delimiters
327:                    int i = 0;
328:                    while (i < k.length() && k.charAt(i) == PROPERTY_DELIMITER) {
329:                        i++;
330:                    }
331:
332:                    if (i < k.length()) {
333:                        result.append(k.substring(i));
334:                    }
335:                }
336:
337:                return result;
338:            }
339:
340:            /**
341:             * Helper method for comparing two key parts.
342:             *
343:             * @param it1 the iterator with the first part
344:             * @param it2 the iterator with the second part
345:             * @return a flag if both parts are equal
346:             */
347:            private static boolean partsEqual(KeyIterator it1, KeyIterator it2) {
348:                return it1.nextKey().equals(it2.nextKey())
349:                        && it1.getIndex() == it2.getIndex()
350:                        && it1.isAttribute() == it2.isAttribute();
351:            }
352:
353:            /**
354:             * A specialized iterator class for tokenizing a configuration key.
355:             * This class implements the normal iterator interface. In addition it
356:             * provides some specific methods for configuration keys.
357:             */
358:            public class KeyIterator implements  Iterator, Cloneable {
359:                /** Stores the current key name.*/
360:                private String current;
361:
362:                /** Stores the start index of the actual token.*/
363:                private int startIndex;
364:
365:                /** Stores the end index of the actual token.*/
366:                private int endIndex;
367:
368:                /** Stores the index of the actual property if there is one.*/
369:                private int indexValue;
370:
371:                /** Stores a flag if the actual property has an index.*/
372:                private boolean hasIndex;
373:
374:                /** Stores a flag if the actual property is an attribute.*/
375:                private boolean attribute;
376:
377:                /**
378:                 * Helper method for determining the next indices.
379:                 *
380:                 * @return the next key part
381:                 */
382:                private String findNextIndices() {
383:                    startIndex = endIndex;
384:                    // skip empty names
385:                    while (startIndex < keyBuffer.length()
386:                            && keyBuffer.charAt(startIndex) == PROPERTY_DELIMITER) {
387:                        startIndex++;
388:                    }
389:
390:                    // Key ends with a delimiter?
391:                    if (startIndex >= keyBuffer.length()) {
392:                        endIndex = keyBuffer.length();
393:                        startIndex = endIndex - 1;
394:                        return keyBuffer.substring(startIndex, endIndex);
395:                    } else {
396:                        return nextKeyPart();
397:                    }
398:                }
399:
400:                /**
401:                 * Helper method for extracting the next key part. Takes escaping of
402:                 * delimiter characters into account.
403:                 *
404:                 * @return the next key part
405:                 */
406:                private String nextKeyPart() {
407:                    StringBuffer key = new StringBuffer(INITIAL_SIZE);
408:                    int idx = startIndex;
409:                    int endIdx = keyBuffer.toString().indexOf(ATTRIBUTE_START,
410:                            startIndex);
411:                    if (endIdx < 0 || endIdx == startIndex) {
412:                        endIdx = keyBuffer.length();
413:                    }
414:                    boolean found = false;
415:
416:                    while (!found && idx < endIdx) {
417:                        char c = keyBuffer.charAt(idx);
418:                        if (c == PROPERTY_DELIMITER) {
419:                            // a duplicated delimiter means escaping
420:                            if (idx == endIdx - 1
421:                                    || keyBuffer.charAt(idx + 1) != PROPERTY_DELIMITER) {
422:                                found = true;
423:                            } else {
424:                                idx++;
425:                            }
426:                        }
427:                        if (!found) {
428:                            key.append(c);
429:                            idx++;
430:                        }
431:                    }
432:
433:                    endIndex = idx;
434:                    return key.toString();
435:                }
436:
437:                /**
438:                 * Returns the next key part of this configuration key. This is a short
439:                 * form of <code>nextKey(false)</code>.
440:                 *
441:                 * @return the next key part
442:                 */
443:                public String nextKey() {
444:                    return nextKey(false);
445:                }
446:
447:                /**
448:                 * Returns the next key part of this configuration key. The boolean
449:                 * parameter indicates wheter a decorated key should be returned. This
450:                 * affects only attribute keys: if the parameter is <b>false</b>, the
451:                 * attribute markers are stripped from the key; if it is <b>true</b>,
452:                 * they remain.
453:                 *
454:                 * @param decorated a flag if the decorated key is to be returned
455:                 * @return the next key part
456:                 */
457:                public String nextKey(boolean decorated) {
458:                    if (!hasNext()) {
459:                        throw new NoSuchElementException("No more key parts!");
460:                    }
461:
462:                    hasIndex = false;
463:                    indexValue = -1;
464:                    String key = findNextIndices();
465:
466:                    current = key;
467:                    hasIndex = checkIndex(key);
468:                    attribute = checkAttribute(current);
469:
470:                    return currentKey(decorated);
471:                }
472:
473:                /**
474:                 * Helper method for checking if the passed key is an attribute.
475:                 * If this is the case, the internal fields will be set.
476:                 *
477:                 * @param key the key to be checked
478:                 * @return a flag if the key is an attribute
479:                 */
480:                private boolean checkAttribute(String key) {
481:                    if (isAttributeKey(key)) {
482:                        current = removeAttributeMarkers(key);
483:                        return true;
484:                    } else {
485:                        return false;
486:                    }
487:                }
488:
489:                /**
490:                 * Helper method for checking if the passed key contains an index.
491:                 * If this is the case, internal fields will be set.
492:                 *
493:                 * @param key the key to be checked
494:                 * @return a flag if an index is defined
495:                 */
496:                private boolean checkIndex(String key) {
497:                    boolean result = false;
498:
499:                    int idx = key.lastIndexOf(INDEX_START);
500:                    if (idx > 0) {
501:                        int endidx = key.indexOf(INDEX_END, idx);
502:
503:                        if (endidx > idx + 1) {
504:                            indexValue = Integer.parseInt(key.substring(
505:                                    idx + 1, endidx));
506:                            current = key.substring(0, idx);
507:                            result = true;
508:                        }
509:                    }
510:
511:                    return result;
512:                }
513:
514:                /**
515:                 * Checks if there is a next element.
516:                 *
517:                 * @return a flag if there is a next element
518:                 */
519:                public boolean hasNext() {
520:                    return endIndex < keyBuffer.length();
521:                }
522:
523:                /**
524:                 * Returns the next object in the iteration.
525:                 *
526:                 * @return the next object
527:                 */
528:                public Object next() {
529:                    return nextKey();
530:                }
531:
532:                /**
533:                 * Removes the current object in the iteration. This method is not
534:                 * supported by this iterator type, so an exception is thrown.
535:                 */
536:                public void remove() {
537:                    throw new UnsupportedOperationException(
538:                            "Remove not supported!");
539:                }
540:
541:                /**
542:                 * Returns the current key of the iteration (without skipping to the
543:                 * next element). This is the same key the previous <code>next()</code>
544:                 * call had returned. (Short form of <code>currentKey(false)</code>.
545:                 *
546:                 * @return the current key
547:                 */
548:                public String currentKey() {
549:                    return currentKey(false);
550:                }
551:
552:                /**
553:                 * Returns the current key of the iteration (without skipping to the
554:                 * next element). The boolean parameter indicates wheter a decorated
555:                 * key should be returned. This affects only attribute keys: if the
556:                 * parameter is <b>false</b>, the attribute markers are stripped from
557:                 * the key; if it is <b>true</b>, they remain.
558:                 *
559:                 * @param decorated a flag if the decorated key is to be returned
560:                 * @return the current key
561:                 */
562:                public String currentKey(boolean decorated) {
563:                    return (decorated && isAttribute()) ? constructAttributeKey(current)
564:                            : current;
565:                }
566:
567:                /**
568:                 * Returns a flag if the current key is an attribute. This method can
569:                 * be called after <code>next()</code>.
570:                 *
571:                 * @return a flag if the current key is an attribute
572:                 */
573:                public boolean isAttribute() {
574:                    return attribute;
575:                }
576:
577:                /**
578:                 * Returns the index value of the current key. If the current key does
579:                 * not have an index, return value is -1. This method can be called
580:                 * after <code>next()</code>.
581:                 *
582:                 * @return the index value of the current key
583:                 */
584:                public int getIndex() {
585:                    return indexValue;
586:                }
587:
588:                /**
589:                 * Returns a flag if the current key has an associated index.
590:                 * This method can be called after <code>next()</code>.
591:                 *
592:                 * @return a flag if the current key has an index
593:                 */
594:                public boolean hasIndex() {
595:                    return hasIndex;
596:                }
597:
598:                /**
599:                 * Creates a clone of this object.
600:                 *
601:                 * @return a clone of this object
602:                 */
603:                public Object clone() {
604:                    try {
605:                        return super .clone();
606:                    } catch (CloneNotSupportedException cex) {
607:                        // should not happen
608:                        return null;
609:                    }
610:                }
611:            }
612:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.