Source Code Cross Referenced for DefaultExpressionEngine.java in  » Library » Apache-commons-configuration-1.4-src » org » apache » commons » configuration » tree » 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.tree 
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:        package org.apache.commons.configuration.tree;
018:
019:        import java.util.Collection;
020:        import java.util.Iterator;
021:        import java.util.LinkedList;
022:        import java.util.List;
023:
024:        import org.apache.commons.lang.StringUtils;
025:
026:        /**
027:         * <p>
028:         * A default implementation of the <code>ExpressionEngine</code> interface
029:         * providing the &quot;native&quote; expression language for hierarchical
030:         * configurations.
031:         * </p>
032:         * <p>
033:         * This class implements a rather simple expression language for navigating
034:         * through a hierarchy of configuration nodes. It supports the following
035:         * operations:
036:         * </p>
037:         * <p>
038:         * <ul>
039:         * <li>Navigating from a node to one of its children using the child node
040:         * delimiter, which is by the default a dot (&quot;.&quot;).</li>
041:         * <li>Navigating from a node to one of its attributes using the attribute node
042:         * delimiter, which by default follows the XPATH like syntax
043:         * <code>[@&lt;attributeName&gt;]</code>.</li>
044:         * <li>If there are multiple child or attribute nodes with the same name, a
045:         * specific node can be selected using a numerical index. By default indices are
046:         * written in paranthesis.</li>
047:         * </ul>
048:         * </p>
049:         * <p>
050:         * As an example consider the following XML document:
051:         * </p>
052:         *
053:         * <pre>
054:         *  &lt;database&gt;
055:         *    &lt;tables&gt;
056:         *      &lt;table type=&quot;system&quot;&gt;
057:         *        &lt;name&gt;users&lt;/name&gt;
058:         *        &lt;fields&gt;
059:         *          &lt;field&gt;
060:         *            &lt;name&gt;lid&lt;/name&gt;
061:         *            &lt;type&gt;long&lt;/name&gt;
062:         *          &lt;/field&gt;
063:         *          &lt;field&gt;
064:         *            &lt;name&gt;usrName&lt;/name&gt;
065:         *            &lt;type&gt;java.lang.String&lt;/type&gt;
066:         *          &lt;/field&gt;
067:         *         ...
068:         *        &lt;/fields&gt;
069:         *      &lt;/table&gt;
070:         *      &lt;table&gt;
071:         *        &lt;name&gt;documents&lt;/name&gt;
072:         *        &lt;fields&gt;
073:         *          &lt;field&gt;
074:         *            &lt;name&gt;docid&lt;/name&gt;
075:         *            &lt;type&gt;long&lt;/type&gt;
076:         *          &lt;/field&gt;
077:         *          ...
078:         *        &lt;/fields&gt;
079:         *      &lt;/table&gt;
080:         *      ...
081:         *    &lt;/tables&gt;
082:         *  &lt;/database&gt;
083:         * </pre>
084:         *
085:         * </p>
086:         * <p>
087:         * If this document is parsed and stored in a hierarchical configuration object,
088:         * for instance the key <code>tables.table(0).name</code> can be used to find
089:         * out the name of the first table. In opposite <code>tables.table.name</code>
090:         * would return a collection with the names of all available tables. Similarily
091:         * the key <code>tables.table(1).fields.field.name</code> returns a collection
092:         * with the names of all fields of the second table. If another index is added
093:         * after the <code>field</code> element, a single field can be accessed:
094:         * <code>tables.table(1).fields.field(0).name</code>. The key
095:         * <code>tables.table(0)[@type]</code> would select the type attribute of the
096:         * first table.
097:         * </p>
098:         * <p>
099:         * This example works with the default values for delimiters and index markers.
100:         * It is also possible to set custom values for these properties so that you can
101:         * adapt a <code>DefaultExpressionEngine</code> to your personal needs.
102:         * </p>
103:         *
104:         * @since 1.3
105:         * @author Oliver Heger
106:         * @version $Id: DefaultExpressionEngine.java 439648 2006-09-02 20:42:10Z oheger $
107:         */
108:        public class DefaultExpressionEngine implements  ExpressionEngine {
109:            /** Constant for the default property delimiter. */
110:            public static final String DEFAULT_PROPERTY_DELIMITER = ".";
111:
112:            /** Constant for the default escaped property delimiter. */
113:            public static final String DEFAULT_ESCAPED_DELIMITER = DEFAULT_PROPERTY_DELIMITER
114:                    + DEFAULT_PROPERTY_DELIMITER;
115:
116:            /** Constant for the default attribute start marker. */
117:            public static final String DEFAULT_ATTRIBUTE_START = "[@";
118:
119:            /** Constant for the default attribute end marker. */
120:            public static final String DEFAULT_ATTRIBUTE_END = "]";
121:
122:            /** Constant for the default index start marker. */
123:            public static final String DEFAULT_INDEX_START = "(";
124:
125:            /** Constant for the default index end marker. */
126:            public static final String DEFAULT_INDEX_END = ")";
127:
128:            /** Stores the property delimiter. */
129:            private String propertyDelimiter = DEFAULT_PROPERTY_DELIMITER;
130:
131:            /** Stores the escaped property delimiter. */
132:            private String escapedDelimiter = DEFAULT_ESCAPED_DELIMITER;
133:
134:            /** Stores the attribute start marker. */
135:            private String attributeStart = DEFAULT_ATTRIBUTE_START;
136:
137:            /** Stores the attribute end marker. */
138:            private String attributeEnd = DEFAULT_ATTRIBUTE_END;
139:
140:            /** Stores the index start marker. */
141:            private String indexStart = DEFAULT_INDEX_START;
142:
143:            /** stores the index end marker. */
144:            private String indexEnd = DEFAULT_INDEX_END;
145:
146:            /**
147:             * Sets the attribute end marker.
148:             *
149:             * @return the attribute end marker
150:             */
151:            public String getAttributeEnd() {
152:                return attributeEnd;
153:            }
154:
155:            /**
156:             * Sets the attribute end marker.
157:             *
158:             * @param attributeEnd the attribute end marker; can be <b>null</b> if no
159:             * end marker is needed
160:             */
161:            public void setAttributeEnd(String attributeEnd) {
162:                this .attributeEnd = attributeEnd;
163:            }
164:
165:            /**
166:             * Returns the attribute start marker.
167:             *
168:             * @return the attribute start marker
169:             */
170:            public String getAttributeStart() {
171:                return attributeStart;
172:            }
173:
174:            /**
175:             * Sets the attribute start marker. Attribute start and end marker are used
176:             * together to detect attributes in a property key.
177:             *
178:             * @param attributeStart the attribute start marker
179:             */
180:            public void setAttributeStart(String attributeStart) {
181:                this .attributeStart = attributeStart;
182:            }
183:
184:            /**
185:             * Returns the escaped property delimiter string.
186:             *
187:             * @return the escaped property delimiter
188:             */
189:            public String getEscapedDelimiter() {
190:                return escapedDelimiter;
191:            }
192:
193:            /**
194:             * Sets the escaped property delimiter string. With this string a delimiter
195:             * that belongs to the key of a property can be escaped. If for instance
196:             * &quot;.&quot; is used as property delimiter, you can set the escaped
197:             * delimiter to &quot;\.&quot; and can then escape the delimiter with a back
198:             * slash.
199:             *
200:             * @param escapedDelimiter the escaped delimiter string
201:             */
202:            public void setEscapedDelimiter(String escapedDelimiter) {
203:                this .escapedDelimiter = escapedDelimiter;
204:            }
205:
206:            /**
207:             * Returns the index end marker.
208:             *
209:             * @return the index end marker
210:             */
211:            public String getIndexEnd() {
212:                return indexEnd;
213:            }
214:
215:            /**
216:             * Sets the index end marker.
217:             *
218:             * @param indexEnd the index end marker
219:             */
220:            public void setIndexEnd(String indexEnd) {
221:                this .indexEnd = indexEnd;
222:            }
223:
224:            /**
225:             * Returns the index start marker.
226:             *
227:             * @return the index start marker
228:             */
229:            public String getIndexStart() {
230:                return indexStart;
231:            }
232:
233:            /**
234:             * Sets the index start marker. Index start and end marker are used together
235:             * to detect indices in a property key.
236:             *
237:             * @param indexStart the index start marker
238:             */
239:            public void setIndexStart(String indexStart) {
240:                this .indexStart = indexStart;
241:            }
242:
243:            /**
244:             * Returns the property delimiter.
245:             *
246:             * @return the property delimiter
247:             */
248:            public String getPropertyDelimiter() {
249:                return propertyDelimiter;
250:            }
251:
252:            /**
253:             * Sets the property delmiter. This string is used to split the parts of a
254:             * property key.
255:             *
256:             * @param propertyDelimiter the property delimiter
257:             */
258:            public void setPropertyDelimiter(String propertyDelimiter) {
259:                this .propertyDelimiter = propertyDelimiter;
260:            }
261:
262:            /**
263:             * Evaluates the given key and returns all matching nodes. This method
264:             * supports the syntax as described in the class comment.
265:             *
266:             * @param root the root node
267:             * @param key the key
268:             * @return a list with the matching nodes
269:             */
270:            public List query(ConfigurationNode root, String key) {
271:                List nodes = new LinkedList();
272:                findNodesForKey(new DefaultConfigurationKey(this , key)
273:                        .iterator(), root, nodes);
274:                return nodes;
275:            }
276:
277:            /**
278:             * Determines the key of the passed in node. This implementation takes the
279:             * given parent key, adds a property delimiter, and then adds the node's
280:             * name. (For attribute nodes the attribute delimiters are used instead.)
281:             * The name of the root node is a blanc string. Note that no indices will be
282:             * returned.
283:             *
284:             * @param node the node whose key is to be determined
285:             * @param parentKey the key of this node's parent
286:             * @return the key for the given node
287:             */
288:            public String nodeKey(ConfigurationNode node, String parentKey) {
289:                if (parentKey == null) {
290:                    // this is the root node
291:                    return StringUtils.EMPTY;
292:                }
293:
294:                else {
295:                    DefaultConfigurationKey key = new DefaultConfigurationKey(
296:                            this , parentKey);
297:                    if (node.isAttribute()) {
298:                        key.appendAttribute(node.getName());
299:                    } else {
300:                        key.append(node.getName(), true);
301:                    }
302:                    return key.toString();
303:                }
304:            }
305:
306:            /**
307:             * <p>
308:             * Prepares Adding the property with the specified key.
309:             * </p>
310:             * <p>
311:             * To be able to deal with the structure supported by hierarchical
312:             * configuration implementations the passed in key is of importance,
313:             * especially the indices it might contain. The following example should
314:             * clearify this: Suppose the actual node structure looks like the
315:             * following:
316:             * </p>
317:             * <p>
318:             * <pre>
319:             *  tables
320:             *     +-- table
321:             *             +-- name = user
322:             *             +-- fields
323:             *                     +-- field
324:             *                             +-- name = uid
325:             *                     +-- field
326:             *                             +-- name = firstName
327:             *                     ...
328:             *     +-- table
329:             *             +-- name = documents
330:             *             +-- fields
331:             *                    ...
332:             * </pre>
333:             * </p>
334:             * <p>
335:             * In this example a database structure is defined, e.g. all fields of the
336:             * first table could be accessed using the key
337:             * <code>tables.table(0).fields.field.name</code>. If now properties are
338:             * to be added, it must be exactly specified at which position in the
339:             * hierarchy the new property is to be inserted. So to add a new field name
340:             * to a table it is not enough to say just
341:             * </p>
342:             * <p>
343:             * <pre>
344:             * config.addProperty(&quot;tables.table.fields.field.name&quot;, &quot;newField&quot;);
345:             * </pre>
346:             * </p>
347:             * <p>
348:             * The statement given above contains some ambiguity. For instance it is not
349:             * clear, to which table the new field should be added. If this method finds
350:             * such an ambiguity, it is resolved by following the last valid path. Here
351:             * this would be the last table. The same is true for the <code>field</code>;
352:             * because there are multiple fields and no explicit index is provided, a
353:             * new <code>name</code> property would be added to the last field - which
354:             * is propably not what was desired.
355:             * </p>
356:             * <p>
357:             * To make things clear explicit indices should be provided whenever
358:             * possible. In the example above the exact table could be specified by
359:             * providing an index for the <code>table</code> element as in
360:             * <code>tables.table(1).fields</code>. By specifying an index it can
361:             * also be expressed that at a given position in the configuration tree a
362:             * new branch should be added. In the example above we did not want to add
363:             * an additional <code>name</code> element to the last field of the table,
364:             * but we want a complete new <code>field</code> element. This can be
365:             * achieved by specifying an invalid index (like -1) after the element where
366:             * a new branch should be created. Given this our example would run:
367:             * </p>
368:             * <p>
369:             * <pre>
370:             * config.addProperty(&quot;tables.table(1).fields.field(-1).name&quot;, &quot;newField&quot;);
371:             * </pre>
372:             * </p>
373:             * <p>
374:             * With this notation it is possible to add new branches everywhere. We
375:             * could for instance create a new <code>table</code> element by
376:             * specifying
377:             * </p>
378:             * <p>
379:             * <pre>
380:             * config.addProperty(&quot;tables.table(-1).fields.field.name&quot;, &quot;newField2&quot;);
381:             * </pre>
382:             * </p>
383:             * <p>
384:             * (Note that because after the <code>table</code> element a new branch is
385:             * created indices in following elements are not relevant; the branch is new
386:             * so there cannot be any ambiguities.)
387:             * </p>
388:             *
389:             * @param root the root node of the nodes hierarchy
390:             * @param key the key of the new property
391:             * @return a data object with information needed for the add operation
392:             */
393:            public NodeAddData prepareAdd(ConfigurationNode root, String key) {
394:                DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey(
395:                        this , key).iterator();
396:                if (!it.hasNext()) {
397:                    throw new IllegalArgumentException(
398:                            "Key for add operation must be defined!");
399:                }
400:
401:                NodeAddData result = new NodeAddData();
402:                result.setParent(findLastPathNode(it, root));
403:
404:                while (it.hasNext()) {
405:                    if (!it.isPropertyKey()) {
406:                        throw new IllegalArgumentException(
407:                                "Invalid key for add operation: " + key
408:                                        + " (Attribute key in the middle.)");
409:                    }
410:                    result.addPathNode(it.currentKey());
411:                    it.next();
412:                }
413:
414:                result.setNewNodeName(it.currentKey());
415:                result.setAttribute(!it.isPropertyKey());
416:                return result;
417:            }
418:
419:            /**
420:             * Recursive helper method for evaluating a key. This method processes all
421:             * facets of a configuration key, traverses the tree of properties and
422:             * fetches the the nodes of all matching properties.
423:             *
424:             * @param keyPart the configuration key iterator
425:             * @param node the actual node
426:             * @param nodes here the found nodes are stored
427:             */
428:            protected void findNodesForKey(
429:                    DefaultConfigurationKey.KeyIterator keyPart,
430:                    ConfigurationNode node, Collection nodes) {
431:                if (!keyPart.hasNext()) {
432:                    nodes.add(node);
433:                }
434:
435:                else {
436:                    String key = keyPart.nextKey(false);
437:                    if (keyPart.isPropertyKey()) {
438:                        processSubNodes(keyPart, node.getChildren(key), nodes);
439:                    }
440:                    if (keyPart.isAttribute()) {
441:                        processSubNodes(keyPart, node.getAttributes(key), nodes);
442:                    }
443:                }
444:            }
445:
446:            /**
447:             * Finds the last existing node for an add operation. This method traverses
448:             * the configuration node tree along the specified key. The last existing
449:             * node on this path is returned.
450:             *
451:             * @param keyIt the key iterator
452:             * @param node the actual node
453:             * @return the last existing node on the given path
454:             */
455:            protected ConfigurationNode findLastPathNode(
456:                    DefaultConfigurationKey.KeyIterator keyIt,
457:                    ConfigurationNode node) {
458:                String keyPart = keyIt.nextKey(false);
459:
460:                if (keyIt.hasNext()) {
461:                    if (!keyIt.isPropertyKey()) {
462:                        // Attribute keys can only appear as last elements of the path
463:                        throw new IllegalArgumentException(
464:                                "Invalid path for add operation: "
465:                                        + "Attribute key in the middle!");
466:                    }
467:                    int idx = keyIt.hasIndex() ? keyIt.getIndex() : node
468:                            .getChildrenCount(keyPart) - 1;
469:                    if (idx < 0 || idx >= node.getChildrenCount(keyPart)) {
470:                        return node;
471:                    } else {
472:                        return findLastPathNode(keyIt, (ConfigurationNode) node
473:                                .getChildren(keyPart).get(idx));
474:                    }
475:                }
476:
477:                else {
478:                    return node;
479:                }
480:            }
481:
482:            /**
483:             * Called by <code>findNodesForKey()</code> to process the sub nodes of
484:             * the current node depending on the type of the current key part (children,
485:             * attributes, or both).
486:             *
487:             * @param keyPart the key part
488:             * @param subNodes a list with the sub nodes to process
489:             * @param nodes the target collection
490:             */
491:            private void processSubNodes(
492:                    DefaultConfigurationKey.KeyIterator keyPart, List subNodes,
493:                    Collection nodes) {
494:                if (keyPart.hasIndex()) {
495:                    if (keyPart.getIndex() >= 0
496:                            && keyPart.getIndex() < subNodes.size()) {
497:                        findNodesForKey(
498:                                (DefaultConfigurationKey.KeyIterator) keyPart
499:                                        .clone(), (ConfigurationNode) subNodes
500:                                        .get(keyPart.getIndex()), nodes);
501:                    }
502:                } else {
503:                    for (Iterator it = subNodes.iterator(); it.hasNext();) {
504:                        findNodesForKey(
505:                                (DefaultConfigurationKey.KeyIterator) keyPart
506:                                        .clone(),
507:                                (ConfigurationNode) it.next(), nodes);
508:                    }
509:                }
510:            }
511:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.