Source Code Cross Referenced for CombinedConfiguration.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:        package org.apache.commons.configuration;
018:
019:        import java.util.ArrayList;
020:        import java.util.Collection;
021:        import java.util.HashMap;
022:        import java.util.Iterator;
023:        import java.util.List;
024:        import java.util.Map;
025:        import java.util.Set;
026:
027:        import org.apache.commons.configuration.event.ConfigurationEvent;
028:        import org.apache.commons.configuration.event.ConfigurationListener;
029:        import org.apache.commons.configuration.tree.ConfigurationNode;
030:        import org.apache.commons.configuration.tree.DefaultConfigurationKey;
031:        import org.apache.commons.configuration.tree.DefaultConfigurationNode;
032:        import org.apache.commons.configuration.tree.DefaultExpressionEngine;
033:        import org.apache.commons.configuration.tree.NodeCombiner;
034:        import org.apache.commons.configuration.tree.UnionCombiner;
035:        import org.apache.commons.configuration.tree.ViewNode;
036:
037:        /**
038:         * <p>
039:         * A hierarchical composite configuration class.
040:         * </p>
041:         * <p>
042:         * This class maintains a list of configuration objects, which can be added
043:         * using the divers <code>addConfiguration()</code> methods. After that the
044:         * configurations can be accessed either by name (if one was provided when the
045:         * configuration was added) or by index. For the whole set of managed
046:         * configurations a logical node structure is constructed. For this purpose a
047:         * <code>{@link org.apache.commons.configuration.tree.NodeCombiner NodeCombiner}</code>
048:         * object can be set. This makes it possible to specify different algorithms for
049:         * the combination process.
050:         * </p>
051:         * <p>
052:         * The big advantage of this class is that it creates a truely hierarchical
053:         * structure of all the properties stored in the contained configurations - even
054:         * if some of them are no hierarchical configurations per se. So all enhanced
055:         * features provided by a hierarchical configuration (e.g. choosing an
056:         * expression engine) are applicable.
057:         * </p>
058:         * <p>
059:         * The class works by registering itself as an event listener add all added
060:         * configurations. So it gets notified whenever one of these configurations is
061:         * changed and can invalidate its internal node structure. The next time a
062:         * property is accessed the node structure will be re-constructed using the
063:         * current state of the managed configurations. Node that, depending on the used
064:         * <code>NodeCombiner</code>, this may be a complex operation.
065:         * </p>
066:         * <p>
067:         * It is not strictly forbidden to manipulate a
068:         * <code>CombinedConfiguration</code> directly, but the results may be
069:         * unpredictable. For instance some node combiners use special view nodes for
070:         * linking parts of the original configurations' data together. If new
071:         * properties are added to such a special node, they do not belong to any of the
072:         * managed configurations and thus hang in the air. It is also possible that
073:         * direct updates on a <code>CombinedConfiguration</code> are incompatible
074:         * with the used node combiner (e.g. if the
075:         * <code>{@link org.apache.commons.configuration.tree.OverrideCombiner OverrideCombiner}</code>
076:         * is used and properties are removed the resulting node structure may be
077:         * incorrect because some properties that were hidden by the removed properties
078:         * are not visible). So it is recommended to perform updates only on the managed
079:         * configurations.
080:         * </p>
081:         * <p>
082:         * Whenever the node structure of a <code>CombinedConfiguration</code> becomes
083:         * invalid (either because one of the contained configurations was modified or
084:         * because the <code>invalidate()</code> method was directly called) an event
085:         * is generated. So this can be detected by interested event listeners. This
086:         * also makes it possible to add a combined configuration into another one.
087:         * </p>
088:         * <p>
089:         * Implementation note: Adding and removing configurations to and from a
090:         * combined configuration is not thread-safe. If a combined configuration is
091:         * manipulated by multiple threads, the developer has to take care about
092:         * properly synchronization.
093:         * </p>
094:         *
095:         * @author <a
096:         * href="http://jakarta.apache.org/commons/configuration/team-list.html">Commons
097:         * Configuration team</a>
098:         * @since 1.3
099:         * @version $Id: CombinedConfiguration.java 484692 2006-12-08 18:30:15Z oheger $
100:         */
101:        public class CombinedConfiguration extends HierarchicalConfiguration
102:                implements  ConfigurationListener, Cloneable {
103:            /**
104:             * Constant for the invalidate event that is fired when the internal node
105:             * structure becomes invalid.
106:             */
107:            public static final int EVENT_COMBINED_INVALIDATE = 40;
108:
109:            /**
110:             * The serial version ID.
111:             */
112:            private static final long serialVersionUID = 8338574525528692307L;
113:
114:            /** Constant for the expression engine for parsing the at path. */
115:            private static final DefaultExpressionEngine AT_ENGINE = new DefaultExpressionEngine();
116:
117:            /** Constant for the default node combiner. */
118:            private static final NodeCombiner DEFAULT_COMBINER = new UnionCombiner();
119:
120:            /** Constant for the name of the property used for the reload check.*/
121:            private static final String PROP_RELOAD_CHECK = "CombinedConfigurationReloadCheck";
122:
123:            /** Stores the combiner. */
124:            private NodeCombiner nodeCombiner;
125:
126:            /** Stores the combined root node. */
127:            private ConfigurationNode combinedRoot;
128:
129:            /** Stores a list with the contained configurations. */
130:            private List configurations;
131:
132:            /** Stores a map with the named configurations. */
133:            private Map namedConfigurations;
134:
135:            /** A flag whether an enhanced reload check is to be performed.*/
136:            private boolean forceReloadCheck;
137:
138:            /**
139:             * Creates a new instance of <code>CombinedConfiguration</code> and
140:             * initializes the combiner to be used.
141:             *
142:             * @param comb the node combiner (can be <b>null</b>, then a union combiner
143:             * is used as default)
144:             */
145:            public CombinedConfiguration(NodeCombiner comb) {
146:                setNodeCombiner((comb != null) ? comb : DEFAULT_COMBINER);
147:                clear();
148:            }
149:
150:            /**
151:             * Creates a new instance of <code>CombinedConfiguration</code> that uses
152:             * a union combiner.
153:             *
154:             * @see org.apache.commons.configuration.tree.UnionCombiner
155:             */
156:            public CombinedConfiguration() {
157:                this (null);
158:            }
159:
160:            /**
161:             * Returns the node combiner that is used for creating the combined node
162:             * structure.
163:             *
164:             * @return the node combiner
165:             */
166:            public NodeCombiner getNodeCombiner() {
167:                return nodeCombiner;
168:            }
169:
170:            /**
171:             * Sets the node combiner. This object will be used when the combined node
172:             * structure is to be constructed. It must not be <b>null</b>, otherwise an
173:             * <code>IllegalArgumentException</code> exception is thrown. Changing the
174:             * node combiner causes an invalidation of this combined configuration, so
175:             * that the new combiner immediately takes effect.
176:             *
177:             * @param nodeCombiner the node combiner
178:             */
179:            public void setNodeCombiner(NodeCombiner nodeCombiner) {
180:                if (nodeCombiner == null) {
181:                    throw new IllegalArgumentException(
182:                            "Node combiner must not be null!");
183:                }
184:                this .nodeCombiner = nodeCombiner;
185:                invalidate();
186:            }
187:
188:            /**
189:             * Returns a flag whether an enhanced reload check must be performed.
190:             *
191:             * @return the force reload check flag
192:             * @since 1.4
193:             */
194:            public boolean isForceReloadCheck() {
195:                return forceReloadCheck;
196:            }
197:
198:            /**
199:             * Sets the force reload check flag. If this flag is set, each property
200:             * access on this configuration will cause a reload check on the contained
201:             * configurations. This is a workaround for a problem with some reload
202:             * implementations that only check if a reload is required when they are
203:             * triggered. Per default this mode is disabled. If the force reload check
204:             * flag is set to <b>true</b>, accessing properties will be less
205:             * performant, but reloads on contained configurations will be detected.
206:             *
207:             * @param forceReloadCheck the value of the flag
208:             * @since 1.4
209:             */
210:            public void setForceReloadCheck(boolean forceReloadCheck) {
211:                this .forceReloadCheck = forceReloadCheck;
212:            }
213:
214:            /**
215:             * Adds a new configuration to this combined configuration. It is possible
216:             * (but not mandatory) to give the new configuration a name. This name must
217:             * be unique, otherwise a <code>ConfigurationRuntimeException</code> will
218:             * be thrown. With the optional <code>at</code> argument you can specify
219:             * where in the resulting node structure the content of the added
220:             * configuration should appear. This is a string that uses dots as property
221:             * delimiters (independent on the current expression engine). For instance
222:             * if you pass in the string <code>&quot;database.tables&quot;</code>,
223:             * all properties of the added configuration will occur in this branch.
224:             *
225:             * @param config the configuration to add (must not be <b>null</b>)
226:             * @param name the name of this configuration (can be <b>null</b>)
227:             * @param at the position of this configuration in the combined tree (can be
228:             * <b>null</b>)
229:             */
230:            public void addConfiguration(AbstractConfiguration config,
231:                    String name, String at) {
232:                if (config == null) {
233:                    throw new IllegalArgumentException(
234:                            "Added configuration must not be null!");
235:                }
236:                if (name != null && namedConfigurations.containsKey(name)) {
237:                    throw new ConfigurationRuntimeException(
238:                            "A configuration with the name '"
239:                                    + name
240:                                    + "' already exists in this combined configuration!");
241:                }
242:
243:                ConfigData cd = new ConfigData(config, name, at);
244:                configurations.add(cd);
245:                if (name != null) {
246:                    namedConfigurations.put(name, config);
247:                }
248:
249:                config.addConfigurationListener(this );
250:                invalidate();
251:            }
252:
253:            /**
254:             * Adds a new configuration to this combined configuration with an optional
255:             * name. The new configuration's properties will be added under the root of
256:             * the combined node structure.
257:             *
258:             * @param config the configuration to add (must not be <b>null</b>)
259:             * @param name the name of this configuration (can be <b>null</b>)
260:             */
261:            public void addConfiguration(AbstractConfiguration config,
262:                    String name) {
263:                addConfiguration(config, name, null);
264:            }
265:
266:            /**
267:             * Adds a new configuration to this combined configuration. The new
268:             * configuration is not given a name. Its properties will be added under the
269:             * root of the combined node structure.
270:             *
271:             * @param config the configuration to add (must not be <b>null</b>)
272:             */
273:            public void addConfiguration(AbstractConfiguration config) {
274:                addConfiguration(config, null, null);
275:            }
276:
277:            /**
278:             * Returns the number of configurations that are contained in this combined
279:             * configuration.
280:             *
281:             * @return the number of contained configurations
282:             */
283:            public int getNumberOfConfigurations() {
284:                return configurations.size();
285:            }
286:
287:            /**
288:             * Returns the configuration at the specified index. The contained
289:             * configurations are numbered in the order they were added to this combined
290:             * configuration. The index of the first configuration is 0.
291:             *
292:             * @param index the index
293:             * @return the configuration at this index
294:             */
295:            public Configuration getConfiguration(int index) {
296:                ConfigData cd = (ConfigData) configurations.get(index);
297:                return cd.getConfiguration();
298:            }
299:
300:            /**
301:             * Returns the configuration with the given name. This can be <b>null</b>
302:             * if no such configuration exists.
303:             *
304:             * @param name the name of the configuration
305:             * @return the configuration with this name
306:             */
307:            public Configuration getConfiguration(String name) {
308:                return (Configuration) namedConfigurations.get(name);
309:            }
310:
311:            /**
312:             * Removes the specified configuration from this combined configuration.
313:             *
314:             * @param config the configuration to be removed
315:             * @return a flag whether this configuration was found and could be removed
316:             */
317:            public boolean removeConfiguration(Configuration config) {
318:                for (int index = 0; index < getNumberOfConfigurations(); index++) {
319:                    if (((ConfigData) configurations.get(index))
320:                            .getConfiguration() == config) {
321:                        removeConfigurationAt(index);
322:                        return true;
323:                    }
324:                }
325:
326:                return false;
327:            }
328:
329:            /**
330:             * Removes the configuration at the specified index.
331:             *
332:             * @param index the index
333:             * @return the removed configuration
334:             */
335:            public Configuration removeConfigurationAt(int index) {
336:                ConfigData cd = (ConfigData) configurations.remove(index);
337:                if (cd.getName() != null) {
338:                    namedConfigurations.remove(cd.getName());
339:                }
340:                cd.getConfiguration().removeConfigurationListener(this );
341:                invalidate();
342:                return cd.getConfiguration();
343:            }
344:
345:            /**
346:             * Removes the configuration with the specified name.
347:             *
348:             * @param name the name of the configuration to be removed
349:             * @return the removed configuration (<b>null</b> if this configuration
350:             * was not found)
351:             */
352:            public Configuration removeConfiguration(String name) {
353:                Configuration conf = getConfiguration(name);
354:                if (conf != null) {
355:                    removeConfiguration(conf);
356:                }
357:                return conf;
358:            }
359:
360:            /**
361:             * Returns a set with the names of all configurations contained in this
362:             * combined configuration. Of course here are only these configurations
363:             * listed, for which a name was specified when they were added.
364:             *
365:             * @return a set with the names of the contained configurations (never
366:             * <b>null</b>)
367:             */
368:            public Set getConfigurationNames() {
369:                return namedConfigurations.keySet();
370:            }
371:
372:            /**
373:             * Invalidates this combined configuration. This means that the next time a
374:             * property is accessed the combined node structure must be re-constructed.
375:             * Invalidation of a combined configuration also means that an event of type
376:             * <code>EVENT_COMBINED_INVALIDATE</code> is fired. Note that while other
377:             * events most times appear twice (once before and once after an update),
378:             * this event is only fired once (after update).
379:             */
380:            public void invalidate() {
381:                synchronized (getNodeCombiner()) // use combiner as lock
382:                {
383:                    combinedRoot = null;
384:                }
385:                fireEvent(EVENT_COMBINED_INVALIDATE, null, null, false);
386:            }
387:
388:            /**
389:             * Event listener call back for configuration update events. This method is
390:             * called whenever one of the contained configurations was modified. It
391:             * invalidates this combined configuration.
392:             *
393:             * @param event the update event
394:             */
395:            public void configurationChanged(ConfigurationEvent event) {
396:                invalidate();
397:            }
398:
399:            /**
400:             * Returns the configuration root node of this combined configuration. This
401:             * method will construct a combined node structure using the current node
402:             * combiner if necessary.
403:             *
404:             * @return the combined root node
405:             */
406:            public ConfigurationNode getRootNode() {
407:                synchronized (getNodeCombiner()) {
408:                    if (combinedRoot == null) {
409:                        combinedRoot = constructCombinedNode();
410:                    }
411:                    return combinedRoot;
412:                }
413:            }
414:
415:            /**
416:             * Clears this configuration. All contained configurations will be removed.
417:             */
418:            public void clear() {
419:                fireEvent(EVENT_CLEAR, null, null, true);
420:                configurations = new ArrayList();
421:                namedConfigurations = new HashMap();
422:                fireEvent(EVENT_CLEAR, null, null, false);
423:                invalidate();
424:            }
425:
426:            /**
427:             * Returns a copy of this object. This implementation performs a deep clone,
428:             * i.e. all contained configurations will be cloned, too. For this to work,
429:             * all contained configurations must be cloneable. Registered event
430:             * listeners won't be cloned. The clone will use the same node combiner than
431:             * the original.
432:             *
433:             * @return the copied object
434:             */
435:            public Object clone() {
436:                CombinedConfiguration copy = (CombinedConfiguration) super 
437:                        .clone();
438:                copy.clear();
439:                for (Iterator it = configurations.iterator(); it.hasNext();) {
440:                    ConfigData cd = (ConfigData) it.next();
441:                    copy.addConfiguration(
442:                            (AbstractConfiguration) ConfigurationUtils
443:                                    .cloneConfiguration(cd.getConfiguration()),
444:                            cd.getName(), cd.getAt());
445:                }
446:
447:                copy.setRootNode(new DefaultConfigurationNode());
448:                return copy;
449:            }
450:
451:            /**
452:             * Returns the value of the specified property. This implementation
453:             * evaluates the <em>force reload check</em> flag. If it is set, all
454:             * contained configurations will be triggered before the value of the
455:             * requested property is retrieved.
456:             *
457:             * @param key the key of the desired property
458:             * @return the value of this property
459:             * @since 1.4
460:             */
461:            public Object getProperty(String key) {
462:                if (isForceReloadCheck()) {
463:                    for (Iterator it = configurations.iterator(); it.hasNext();) {
464:                        try {
465:                            // simply retrieve a property; this is enough for
466:                            // triggering a reload
467:                            ((ConfigData) it.next()).getConfiguration()
468:                                    .getProperty(PROP_RELOAD_CHECK);
469:                        } catch (Exception ex) {
470:                            // ignore all exceptions, e.g. missing property exceptions
471:                            ;
472:                        }
473:                    }
474:                }
475:
476:                return super .getProperty(key);
477:            }
478:
479:            /**
480:             * Creates the root node of this combined configuration.
481:             *
482:             * @return the combined root node
483:             */
484:            private ConfigurationNode constructCombinedNode() {
485:                if (getNumberOfConfigurations() < 1) {
486:                    return new ViewNode();
487:                }
488:
489:                else {
490:                    Iterator it = configurations.iterator();
491:                    ConfigurationNode node = ((ConfigData) it.next())
492:                            .getTransformedRoot();
493:                    while (it.hasNext()) {
494:                        node = getNodeCombiner().combine(node,
495:                                ((ConfigData) it.next()).getTransformedRoot());
496:                    }
497:                    return node;
498:                }
499:            }
500:
501:            /**
502:             * An internal helper class for storing information about contained
503:             * configurations.
504:             */
505:            static class ConfigData {
506:                /** Stores a reference to the configuration. */
507:                private AbstractConfiguration configuration;
508:
509:                /** Stores the name under which the configuration is stored. */
510:                private String name;
511:
512:                /** Stores the at information as path of nodes. */
513:                private Collection atPath;
514:
515:                /** Stores the at string.*/
516:                private String at;
517:
518:                /**
519:                 * Creates a new instance of <code>ConfigData</code> and initializes
520:                 * it.
521:                 *
522:                 * @param config the configuration
523:                 * @param n the name
524:                 * @param at the at position
525:                 */
526:                public ConfigData(AbstractConfiguration config, String n,
527:                        String at) {
528:                    configuration = config;
529:                    name = n;
530:                    atPath = parseAt(at);
531:                    this .at = at;
532:                }
533:
534:                /**
535:                 * Returns the stored configuration.
536:                 *
537:                 * @return the configuration
538:                 */
539:                public AbstractConfiguration getConfiguration() {
540:                    return configuration;
541:                }
542:
543:                /**
544:                 * Returns the configuration's name.
545:                 *
546:                 * @return the name
547:                 */
548:                public String getName() {
549:                    return name;
550:                }
551:
552:                /**
553:                 * Returns the at position of this configuration.
554:                 *
555:                 * @return the at position
556:                 */
557:                public String getAt() {
558:                    return at;
559:                }
560:
561:                /**
562:                 * Returns the transformed root node of the stored configuration. The
563:                 * term &quot;transformed&quot; means that an eventually defined at path
564:                 * has been applied.
565:                 *
566:                 * @return the transformed root node
567:                 */
568:                public ConfigurationNode getTransformedRoot() {
569:                    ViewNode result = new ViewNode();
570:                    ViewNode atParent = result;
571:
572:                    if (atPath != null) {
573:                        // Build the complete path
574:                        for (Iterator it = atPath.iterator(); it.hasNext();) {
575:                            ViewNode node = new ViewNode();
576:                            node.setName((String) it.next());
577:                            atParent.addChild(node);
578:                            atParent = node;
579:                        }
580:                    }
581:
582:                    // Copy data of the root node to the new path
583:                    HierarchicalConfiguration hc = ConfigurationUtils
584:                            .convertToHierarchical(getConfiguration());
585:                    atParent.appendChildren(hc.getRootNode());
586:                    atParent.appendAttributes(hc.getRootNode());
587:
588:                    return result;
589:                }
590:
591:                /**
592:                 * Splits the at path into its components.
593:                 *
594:                 * @param at the at string
595:                 * @return a collection with the names of the single components
596:                 */
597:                private Collection parseAt(String at) {
598:                    if (at == null) {
599:                        return null;
600:                    }
601:
602:                    Collection result = new ArrayList();
603:                    DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey(
604:                            AT_ENGINE, at).iterator();
605:                    while (it.hasNext()) {
606:                        result.add(it.nextKey());
607:                    }
608:                    return result;
609:                }
610:            }
611:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.