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 org.apache.commons.configuration.tree.ConfigurationNode;
020:
021: /**
022: * <p>
023: * A specialized hierarchical configuration class that wraps a single node of
024: * its parent configuration.
025: * </p>
026: * <p>
027: * Configurations of this type are initialized with a parent configuration and a
028: * configuration node of this configuration. This node becomes the root node of
029: * the subnode configuration. All property accessor methods are evaluated
030: * relative to this root node. A good use case for a
031: * <code>SubnodeConfiguration</code> is when multiple properties from a
032: * specific sub tree of the whole configuration need to be accessed. Then a
033: * <code>SubnodeConfiguration</code> can be created with the parent node of
034: * the affected sub tree as root node. This allows for simpler property keys and
035: * is also more efficient.
036: * </p>
037: * <p>
038: * A subnode configuration and its parent configuration operate on the same
039: * hierarchy of configuration nodes. So if modifications are performed at the
040: * subnode configuration, these changes are immideately visible in the parent
041: * configuration. Analogously will updates of the parent configuration affect
042: * the subnode configuration if the sub tree spanned by the subnode
043: * configuration's root node is involved.
044: * </p>
045: * <p>
046: * When a subnode configuration is created, it inherits the settings of its
047: * parent configuration, e.g. some flags like the
048: * <code>throwExceptionOnMissing</code> flag or the settings for handling list
049: * delimiters) or the expression engine. If these settings are changed later in
050: * either the subnode or the parent configuration, the changes are not visible
051: * for each other. So you could create a subnode configuration, change its
052: * expression engine without affecting the parent configuration.
053: * </p>
054: * <p>
055: * From its purpose this class is quite similar to
056: * <code>{@link SubsetConfiguration}</code>. The difference is that a subset
057: * configuration of a hierarchical configuration may combine multiple
058: * configuration nodes from different sub trees of the configuration, while all
059: * nodes in a subnode configuration belong to the same sub tree. If an
060: * application can live with this limitation, it is recommended to use this
061: * class instead of <code>SubsetConfiguration</code> because creating a subset
062: * configuration is more expensive than creating a subnode configuration.
063: * </p>
064: *
065: * @since 1.3
066: * @author Oliver Heger
067: * @version $Id: SubnodeConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
068: */
069: public class SubnodeConfiguration extends HierarchicalConfiguration {
070: /**
071: * The serial version UID.
072: */
073: private static final long serialVersionUID = 3105734147019386480L;
074:
075: /** Stores the parent configuration. */
076: private HierarchicalConfiguration parent;
077:
078: /**
079: * Creates a new instance of <code>SubnodeConfiguration</code> and
080: * initializes it with the parent configuration and the new root node.
081: *
082: * @param parent the parent configuration
083: * @param root the root node of this subnode configuration
084: */
085: public SubnodeConfiguration(HierarchicalConfiguration parent,
086: ConfigurationNode root) {
087: if (parent == null) {
088: throw new IllegalArgumentException(
089: "Parent configuration must not be null!");
090: }
091: if (root == null) {
092: throw new IllegalArgumentException(
093: "Root node must not be null!");
094: }
095:
096: setRootNode(root);
097: this .parent = parent;
098: initFromParent(parent);
099: }
100:
101: /**
102: * Returns the parent configuration of this subnode configuration.
103: *
104: * @return the parent configuration
105: */
106: public HierarchicalConfiguration getParent() {
107: return parent;
108: }
109:
110: /**
111: * Returns a hierarchical configuration object for the given sub node.
112: * This implementation will ensure that the returned
113: * <code>SubnodeConfiguration</code> object will have the same parent than
114: * this object.
115: *
116: * @param node the sub node, for which the configuration is to be created
117: * @return a hierarchical configuration for this sub node
118: */
119: protected SubnodeConfiguration createSubnodeConfiguration(
120: ConfigurationNode node) {
121: return new SubnodeConfiguration(getParent(), node);
122: }
123:
124: /**
125: * Creates a new node. This task is delegated to the parent.
126: *
127: * @param name the node's name
128: * @return the new node
129: */
130: protected Node createNode(String name) {
131: return getParent().createNode(name);
132: }
133:
134: /**
135: * Initializes this subnode configuration from the given parent
136: * configuration. This method is called by the constructor. It will copy
137: * many settings from the parent.
138: *
139: * @param parentConfig the parent configuration
140: */
141: protected void initFromParent(HierarchicalConfiguration parentConfig) {
142: setExpressionEngine(parentConfig.getExpressionEngine());
143: setListDelimiter(parentConfig.getListDelimiter());
144: setDelimiterParsingDisabled(parentConfig
145: .isDelimiterParsingDisabled());
146: setThrowExceptionOnMissing(parentConfig
147: .isThrowExceptionOnMissing());
148: }
149:
150: /**
151: * Performs interpolation. This implementation will ask the parent
152: * configuration to perform the interpolation so that variables can be
153: * evaluated in the global context.
154: *
155: * @param value the value to be interpolated
156: */
157: protected Object interpolate(Object value) {
158: return getParent().interpolate(value);
159: }
160: }
|