You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/04/20 21:32:10 UTC
svn commit: r1588831 [3/11] - in /commons/proper/configuration/trunk: ./
src/main/java/org/apache/commons/configuration/
src/main/java/org/apache/commons/configuration/beanutils/
src/main/java/org/apache/commons/configuration/builder/combined/ src/main...
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java Sun Apr 20 19:32:08 2014
@@ -21,6 +21,7 @@ import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -31,15 +32,15 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.event.EventSource;
import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
import org.apache.commons.configuration.sync.LockMode;
-import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.DefaultConfigurationKey;
-import org.apache.commons.configuration.tree.DefaultConfigurationNode;
import org.apache.commons.configuration.tree.DefaultExpressionEngine;
import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.ImmutableNode;
import org.apache.commons.configuration.tree.NodeCombiner;
+import org.apache.commons.configuration.tree.NodeTreeWalker;
+import org.apache.commons.configuration.tree.QueryResult;
import org.apache.commons.configuration.tree.TreeUtils;
import org.apache.commons.configuration.tree.UnionCombiner;
-import org.apache.commons.configuration.tree.ViewNode;
/**
* <p>
@@ -71,21 +72,20 @@ import org.apache.commons.configuration.
* {@code NodeCombiner}, this may be a complex operation.
* </p>
* <p>
- * Because of the way a {@code CombinedConfiguration} is working it has
- * more or less view character: it provides a logic view on the configurations
- * it contains. In this constellation not all methods defined for hierarchical
+ * Because of the way a {@code CombinedConfiguration} is working it has more or
+ * less view character: it provides a logic view on the configurations it
+ * contains. In this constellation not all methods defined for hierarchical
* configurations - especially methods that update the stored properties - can
* be implemented in a consistent manner. Using such methods (like
* {@code addProperty()}, or {@code clearProperty()} on a
- * {@code CombinedConfiguration} is not strictly forbidden, however,
- * depending on the current {@link NodeCombiner} and the involved
- * properties, the results may be different than expected. Some examples may
- * illustrate this:
+ * {@code CombinedConfiguration} is not strictly forbidden, however, depending
+ * on the current {@link NodeCombiner} and the involved properties, the results
+ * may be different than expected. Some examples may illustrate this:
* </p>
* <p>
* <ul>
- * <li>Imagine a {@code CombinedConfiguration} <em>cc</em> containing
- * two child configurations with the following content:
+ * <li>Imagine a {@code CombinedConfiguration} <em>cc</em> containing two child
+ * configurations with the following content:
* <dl>
* <dt>user.properties</dt>
* <dd>
@@ -108,46 +108,47 @@ import org.apache.commons.configuration.
* </dd>
* </dl>
* As a {@code NodeCombiner} a
- * {@link org.apache.commons.configuration.tree.OverrideCombiner OverrideCombiner}
- * is used. This combiner will ensure that defined user settings take precedence
- * over the default values. If the resulting {@code CombinedConfiguration}
- * is queried for the background color, {@code blue} will be returned
- * because this value is defined in {@code user.properties}. Now
- * consider what happens if the key {@code gui.background} is removed
- * from the {@code CombinedConfiguration}:
+ * {@link org.apache.commons.configuration.tree.OverrideCombiner
+ * OverrideCombiner} is used. This combiner will ensure that defined user
+ * settings take precedence over the default values. If the resulting
+ * {@code CombinedConfiguration} is queried for the background color,
+ * {@code blue} will be returned because this value is defined in
+ * {@code user.properties}. Now consider what happens if the key
+ * {@code gui.background} is removed from the {@code CombinedConfiguration}:
*
- * <pre>cc.clearProperty("gui.background");</pre>
+ * <pre>
+ * cc.clearProperty("gui.background");
+ * </pre>
*
- * Will a {@code cc.containsKey("gui.background")} now return <b>false</b>?
- * No, it won't! The {@code clearProperty()} operation is executed on the
- * node set of the combined configuration, which was constructed from the nodes
- * of the two child configurations. It causes the value of the
- * <em>background</em> node to be cleared, which is also part of the first
- * child configuration. This modification of one of its child configurations
- * causes the {@code CombinedConfiguration} to be re-constructed. This
- * time the {@code OverrideCombiner} cannot find a
- * {@code gui.background} property in the first child configuration, but
- * it finds one in the second, and adds it to the resulting combined
- * configuration. So the property is still present (with a different value now).</li>
- * <li>{@code addProperty()} can also be problematic: Most node
- * combiners use special view nodes for linking parts of the original
- * configurations' data together. If new properties are added to such a special
- * node, they do not belong to any of the managed configurations and thus hang
- * in the air. Using the same configurations as in the last example, the
- * statement
+ * Will a {@code cc.containsKey("gui.background")} now return <b>false</b>? No,
+ * it won't! The {@code clearProperty()} operation is executed on the node set
+ * of the combined configuration, which was constructed from the nodes of the
+ * two child configurations. It causes the value of the <em>background</em> node
+ * to be cleared, which is also part of the first child configuration. This
+ * modification of one of its child configurations causes the
+ * {@code CombinedConfiguration} to be re-constructed. This time the
+ * {@code OverrideCombiner} cannot find a {@code gui.background} property in the
+ * first child configuration, but it finds one in the second, and adds it to the
+ * resulting combined configuration. So the property is still present (with a
+ * different value now).</li>
+ * <li>{@code addProperty()} can also be problematic: Most node combiners use
+ * special view nodes for linking parts of the original configurations' data
+ * together. If new properties are added to such a special node, they do not
+ * belong to any of the managed configurations and thus hang in the air. Using
+ * the same configurations as in the last example, the statement
*
* <pre>
- * addProperty("database.user", "scott");
+ * addProperty("database.user", "scott");
* </pre>
*
* would cause such a hanging property. If now one of the child configurations
- * is changed and the {@code CombinedConfiguration} is re-constructed,
- * this property will disappear! (Add operations are not problematic if they
- * result in a child configuration being updated. For instance an
- * {@code addProperty("home.url", "localhost");} will alter the second
- * child configuration - because the prefix <em>home</em> is here already
- * present; when the {@code CombinedConfiguration} is re-constructed,
- * this change is taken into account.)</li>
+ * is changed and the {@code CombinedConfiguration} is re-constructed, this
+ * property will disappear! (Add operations are not problematic if they result
+ * in a child configuration being updated. For instance an
+ * {@code addProperty("home.url", "localhost");} will alter the second child
+ * configuration - because the prefix <em>home</em> is here already present;
+ * when the {@code CombinedConfiguration} is re-constructed, this change is
+ * taken into account.)</li>
* </ul>
* Because of such problems it is recommended to perform updates only on the
* managed child configurations.
@@ -155,26 +156,27 @@ import org.apache.commons.configuration.
* <p>
* Whenever the node structure of a {@code CombinedConfiguration} becomes
* invalid (either because one of the contained configurations was modified or
- * because the {@code invalidate()} method was directly called) an event
- * is generated. So this can be detected by interested event listeners. This
- * also makes it possible to add a combined configuration into another one.
+ * because the {@code invalidate()} method was directly called) an event is
+ * generated. So this can be detected by interested event listeners. This also
+ * makes it possible to add a combined configuration into another one.
* </p>
* <p>
* Notes about thread-safety: This configuration implementation uses a
* {@code Synchronizer} object to protect instances against concurrent access.
* The concrete {@code Synchronizer} implementation used determines whether an
- * instance of this class is thread-safe or not. All methods accessing
- * configuration data or querying or altering this configuration's child
- * configurations are guarded by the {@code Synchronizer}. Because a combined
- * configuration operates on node structures partly owned by its child
- * configurations it makes sense that a single {@code Synchronizer} object is
- * used and shared between all involved configurations (including the combined
- * configuration itself). However, this is not enforced.
+ * instance of this class is thread-safe or not. In contrast to other
+ * implementations derived from {@link BaseHierarchicalConfiguration},
+ * thread-safety is an issue here because the nodes structure used by this
+ * configuration has to be constructed dynamically when a child configuration is
+ * changed. Therefore, when multiple threads are involved which also manipulate
+ * one of the child configurations, a proper {@code Synchronizer} object should
+ * be set. Note that the {@code Synchronizer} objects used by the child
+ * configurations do not really matter. Because immutable in-memory nodes
+ * structures are used for them there is no danger that updates on child
+ * configurations could interfere with read operations on the combined
+ * configuration.
* </p>
*
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
* @since 1.3
* @version $Id$
*/
@@ -198,12 +200,13 @@ public class CombinedConfiguration exten
/** Constant for the default node combiner. */
private static final NodeCombiner DEFAULT_COMBINER = new UnionCombiner();
+ /** Constant for a root node for an empty configuration. */
+ private static final ImmutableNode EMPTY_ROOT = new ImmutableNode.Builder()
+ .create();
+
/** Stores the combiner. */
private NodeCombiner nodeCombiner;
- /** Stores the combined root node. */
- private ConfigurationNode combinedRoot;
-
/** Stores a list with the contained configurations. */
private List<ConfigData> configurations;
@@ -216,6 +219,9 @@ public class CombinedConfiguration exten
*/
private ExpressionEngine conversionExpressionEngine;
+ /** A flag whether this configuration is up-to-date. */
+ private boolean upToDate;
+
/**
* Creates a new instance of {@code CombinedConfiguration} and
* initializes the combiner to be used.
@@ -644,22 +650,6 @@ public class CombinedConfiguration exten
}
/**
- * Returns the configuration root node of this combined configuration. When
- * starting a read or write operation (by obtaining a corresponding lock for
- * this configuration) a combined node structure is constructed if necessary
- * using the current node combiner. This method just returns this combined
- * node. Note that this method should only be called with a lock held!
- * Otherwise, result may be <b>null</b> under certain circumstances.
- *
- * @return the combined root node
- */
- @Override
- public ConfigurationNode getRootNode()
- {
- return combinedRoot;
- }
-
- /**
* Clears this configuration. All contained configurations will be removed.
*/
@Override
@@ -692,7 +682,6 @@ public class CombinedConfiguration exten
.getConfiguration()), cd.getName(), cd.getAt());
}
- copy.setRootNode(new DefaultConfigurationNode());
return copy;
}
finally
@@ -731,28 +720,63 @@ public class CombinedConfiguration exten
throw new IllegalArgumentException("Key must not be null!");
}
+ Set<Configuration> sources = getSources(key);
+ if (sources.isEmpty())
+ {
+ return null;
+ }
+ Iterator<Configuration> iterator = sources.iterator();
+ Configuration source = iterator.next();
+ if (iterator.hasNext())
+ {
+ throw new IllegalArgumentException("The key " + key
+ + " is defined by multiple sources!");
+ }
+ return source;
+ }
+
+ /**
+ * Returns a set with the configuration sources, in which the specified key
+ * is defined. This method determines the configuration nodes that are
+ * identified by the given key. It then determines the configuration sources
+ * to which these nodes belong and adds them to the result set. Note the
+ * following points:
+ * <ul>
+ * <li>If no node object is found for this key, an empty set is returned.</li>
+ * <li>For keys that have been added directly to this combined configuration
+ * and that do not belong to the namespaces defined by existing child
+ * configurations this combined configuration is contained in the result
+ * set.</li>
+ * </ul>
+ *
+ * @param key the key of a configuration property
+ * @return a set with the configuration sources, which contain this property
+ * @since 2.0
+ */
+ public Set<Configuration> getSources(String key)
+ {
beginRead(false);
try
{
- List<ConfigurationNode> nodes = fetchNodeList(key);
- if (nodes.isEmpty())
- {
- return null;
- }
+ List<QueryResult<ImmutableNode>> results = fetchNodeList(key);
+ Set<Configuration> sources = new HashSet<Configuration>();
- Iterator<ConfigurationNode> it = nodes.iterator();
- Configuration source = findSourceConfiguration(it.next());
- while (it.hasNext())
+ for (QueryResult<ImmutableNode> result : results)
{
- Configuration src = findSourceConfiguration(it.next());
- if (src != source)
+ Set<Configuration> resultSources =
+ findSourceConfigurations(result.getNode());
+ if (resultSources.isEmpty())
+ {
+ // key must be defined in combined configuration
+ sources.add(this);
+ }
+ else
{
- throw new IllegalArgumentException("The key " + key
- + " is defined by multiple sources!");
+ sources.addAll(resultSources);
}
}
- return source;
+ return sources;
}
finally
{
@@ -777,8 +801,8 @@ public class CombinedConfiguration exten
boolean lockObtained = false;
do
{
- super.beginRead(optimize);
- if (combinedRoot != null)
+ super.beginRead(false);
+ if (isUpToDate())
{
lockObtained = true;
}
@@ -808,9 +832,11 @@ public class CombinedConfiguration exten
try
{
- if (combinedRoot == null)
+ if (!isUpToDate())
{
- combinedRoot = constructCombinedNode();
+ getSubConfigurationParentModel().replaceRoot(
+ constructCombinedNode(), this);
+ upToDate = true;
}
}
catch (RuntimeException rex)
@@ -821,6 +847,18 @@ public class CombinedConfiguration exten
}
/**
+ * Returns a flag whether this configuration has been invalidated. This
+ * means that the combined nodes structure has to be rebuilt before the
+ * configuration can be accessed.
+ *
+ * @return a flag whether this configuration is invalid
+ */
+ private boolean isUpToDate()
+ {
+ return upToDate;
+ }
+
+ /**
* Marks this configuration as invalid. This means that the next access
* re-creates the root node. An invalidate event is also fired. Note:
* This implementation expects that an exclusive (write) lock is held on
@@ -828,7 +866,7 @@ public class CombinedConfiguration exten
*/
private void invalidateInternal()
{
- combinedRoot = null;
+ upToDate = false;
fireEvent(EVENT_COMBINED_INVALIDATE, null, null, false);
}
@@ -847,7 +885,7 @@ public class CombinedConfiguration exten
*
* @return the combined root node
*/
- private ConfigurationNode constructCombinedNode()
+ private ImmutableNode constructCombinedNode()
{
if (getNumberOfConfigurationsInternal() < 1)
{
@@ -855,13 +893,13 @@ public class CombinedConfiguration exten
{
getLogger().debug("No configurations defined for " + this);
}
- return new ViewNode();
+ return EMPTY_ROOT;
}
else
{
Iterator<ConfigData> it = configurations.iterator();
- ConfigurationNode node = it.next().getTransformedRoot();
+ ImmutableNode node = it.next().getTransformedRoot();
while (it.hasNext())
{
node = nodeCombiner.combine(node,
@@ -879,33 +917,30 @@ public class CombinedConfiguration exten
}
/**
- * Determines the configuration that owns the specified node.
+ * Determines the configurations to which the specified node belongs. This
+ * is done by inspecting the nodes structures of all child configurations.
*
* @param node the node
- * @return the owning configuration
+ * @return a set with the owning configurations
*/
- private Configuration findSourceConfiguration(ConfigurationNode node)
+ private Set<Configuration> findSourceConfigurations(ImmutableNode node)
{
- ConfigurationNode root = null;
- ConfigurationNode current = node;
-
- // find the root node in this hierarchy
- while (current != null)
- {
- root = current;
- current = current.getParentNode();
- }
+ Set<Configuration> result = new HashSet<Configuration>();
+ FindNodeVisitor<ImmutableNode> visitor =
+ new FindNodeVisitor<ImmutableNode>(node);
- // Check with the root nodes of the child configurations
for (ConfigData cd : configurations)
{
- if (root == cd.getRootNode())
+ NodeTreeWalker.INSTANCE.walkBFS(cd.getRootNode(), visitor,
+ getModel().getNodeHandler());
+ if (visitor.isFound())
{
- return cd.getConfiguration();
+ result.add(cd.getConfiguration());
+ visitor.reset();
}
}
- return this;
+ return result;
}
/**
@@ -967,7 +1002,7 @@ public class CombinedConfiguration exten
private final String at;
/** Stores the root node for this child configuration.*/
- private ConfigurationNode rootNode;
+ private ImmutableNode rootNode;
/**
* Creates a new instance of {@code ConfigData} and initializes
@@ -1021,7 +1056,7 @@ public class CombinedConfiguration exten
* @return the root node of this child configuration
* @since 1.5
*/
- public ConfigurationNode getRootNode()
+ public ImmutableNode getRootNode()
{
return rootNode;
}
@@ -1033,41 +1068,83 @@ public class CombinedConfiguration exten
*
* @return the transformed root node
*/
- public ConfigurationNode getTransformedRoot()
+ public ImmutableNode getTransformedRoot()
{
- ViewNode result = new ViewNode();
- ViewNode atParent = result;
+ ImmutableNode configRoot = getRootNodeOfConfiguration();
+ return (atPath == null) ? configRoot : prependAtPath(configRoot);
+ }
- if (atPath != null)
+ /**
+ * Prepends the at path to the given node.
+ *
+ * @param node the root node of the represented configuration
+ * @return the new root node including the at path
+ */
+ private ImmutableNode prependAtPath(ImmutableNode node)
+ {
+ ImmutableNode.Builder pathBuilder = new ImmutableNode.Builder();
+ Iterator<String> pathIterator = atPath.iterator();
+ prependAtPathComponent(pathBuilder, pathIterator.next(),
+ pathIterator, node);
+ return new ImmutableNode.Builder(1).addChild(pathBuilder.create())
+ .create();
+ }
+
+ /**
+ * Handles a single component of the at path. A corresponding node is
+ * created and added to the hierarchical path to the original root node
+ * of the configuration.
+ *
+ * @param builder the current node builder object
+ * @param currentComponent the name of the current path component
+ * @param components an iterator with all components of the at path
+ * @param orgRoot the original root node of the wrapped configuration
+ */
+ private void prependAtPathComponent(ImmutableNode.Builder builder,
+ String currentComponent, Iterator<String> components,
+ ImmutableNode orgRoot)
+ {
+ builder.name(currentComponent);
+ if (components.hasNext())
+ {
+ ImmutableNode.Builder childBuilder =
+ new ImmutableNode.Builder();
+ prependAtPathComponent(childBuilder, components.next(),
+ components, orgRoot);
+ builder.addChild(childBuilder.create());
+ }
+ else
{
- // Build the complete path
- for (String p : atPath)
- {
- ViewNode node = new ViewNode();
- node.setName(p);
- atParent.addChild(node);
- atParent = node;
- }
+ builder.addChildren(orgRoot.getChildren());
+ builder.addAttributes(orgRoot.getAttributes());
+ builder.value(orgRoot.getValue());
}
+ }
- // Copy data of the root node to the new path
+ /**
+ * Obtains the root node of the wrapped configuration. If necessary, a
+ * hierarchical representation of the configuration has to be created
+ * first.
+ *
+ * @return the root node of the associated configuration
+ */
+ private ImmutableNode getRootNodeOfConfiguration()
+ {
getConfiguration().lock(LockMode.READ);
try
{
- ConfigurationNode root =
- ConfigurationUtils.convertToHierarchical(
- getConfiguration(), conversionExpressionEngine)
- .getRootNode();
- atParent.appendChildren(root);
- atParent.appendAttributes(root);
+ ImmutableNode root =
+ ConfigurationUtils
+ .convertToHierarchical(getConfiguration(),
+ conversionExpressionEngine).getNodeModel()
+ .getInMemoryRepresentation();
rootNode = root;
+ return root;
}
finally
{
getConfiguration().unlock(LockMode.READ);
}
-
- return result;
}
/**
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.java Sun Apr 20 19:32:08 2014
@@ -17,6 +17,7 @@
package org.apache.commons.configuration;
+import javax.sql.DataSource;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -28,8 +29,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
-import javax.sql.DataSource;
-
import org.apache.commons.configuration.convert.DisabledListDelimiterHandler;
import org.apache.commons.configuration.convert.ListDelimiterHandler;
import org.apache.commons.lang3.StringUtils;
@@ -329,10 +328,9 @@ public class DatabaseConfiguration exten
{
Object value = extractPropertyValue(rs);
// Split value if it contains the list delimiter
- Iterator<?> it = getListDelimiterHandler().parse(value);
- while (it.hasNext())
+ for (Object o : getListDelimiterHandler().parse(value))
{
- results.add(it.next());
+ results.add(o);
}
}
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.java Sun Apr 20 19:32:08 2014
@@ -34,8 +34,8 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
import org.apache.commons.configuration.interpol.Lookup;
-import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.ImmutableNode;
import org.apache.commons.configuration.tree.NodeCombiner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -60,9 +60,6 @@ import org.apache.commons.logging.LogFac
* </p>
*
* @since 1.6
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
* @version $Id$
*/
public class DynamicCombinedConfiguration extends CombinedConfiguration
@@ -382,13 +379,13 @@ public class DynamicCombinedConfiguratio
* @return the combined root node
*/
@Override
- public ConfigurationNode getRootNode()
+ public ImmutableNode getRootNode()
{
return getCurrentConfig().getRootNode();
}
@Override
- protected void setRootNodeInternal(ConfigurationNode rootNode)
+ protected void setRootNodeInternal(ImmutableNode rootNode)
{
if (configs != null)
{
@@ -665,31 +662,31 @@ public class DynamicCombinedConfiguratio
}
@Override
- protected void addNodesInternal(String key, Collection<? extends ConfigurationNode> nodes)
+ protected void addNodesInternal(String key, Collection<? extends ImmutableNode> nodes)
{
this.getCurrentConfig().addNodes(key, nodes);
}
@Override
- public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key, boolean supportUpdates)
{
return this.getCurrentConfig().configurationAt(key, supportUpdates);
}
@Override
- public SubnodeConfiguration configurationAt(String key)
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key)
{
return this.getCurrentConfig().configurationAt(key);
}
@Override
- public List<SubnodeConfiguration> configurationsAt(String key)
+ public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(String key)
{
return this.getCurrentConfig().configurationsAt(key);
}
@Override
- protected List<ConfigurationNode> clearTreeInternal(String key)
+ protected Object clearTreeInternal(String key)
{
this.getCurrentConfig().clearTree(key);
return Collections.emptyList();
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfiguration.java Sun Apr 20 19:32:08 2014
@@ -19,8 +19,8 @@ package org.apache.commons.configuration
import java.util.Collection;
import java.util.List;
-import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.NodeModelSupport;
/**
* <p>
@@ -28,29 +28,36 @@ import org.apache.commons.configuration.
* </p>
* <p>
* This interface introduces methods for manipulating tree-like structured
- * configuration sources. Also, all methods defined by the
- * {@code Configuration} interface are available.
+ * configuration sources. Also, all methods defined by the {@code Configuration}
+ * interface are available.
+ * </p>
+ * <p>
+ * This interface does not make any assumptions about the concrete type of nodes
+ * used by an implementation; this is reflected by a generic type parameter.
+ * Concrete implementations may therefore define their own hierarchical
+ * structures.
* </p>
*
* @version $Id$
* @since 2.0
+ * @param <T> the type of the nodes used by this hierarchical configuration
*/
-public interface HierarchicalConfiguration
- extends Configuration, ImmutableHierarchicalConfiguration
+public interface HierarchicalConfiguration<T>
+ extends Configuration, ImmutableHierarchicalConfiguration, NodeModelSupport<T>
{
/**
* Returns the root node of this hierarchical configuration.
*
* @return the root node
*/
- ConfigurationNode getRootNode();
+ T getRootNode();
/**
* Sets the root node of this hierarchical configuration.
*
* @param rootNode the root node
*/
- void setRootNode(ConfigurationNode rootNode);
+ void setRootNode(T rootNode);
/**
* Sets the expression engine to be used by this configuration. All property
@@ -68,12 +75,7 @@ public interface HierarchicalConfigurati
* instead of a single property a whole collection of nodes can be added -
* and thus complete configuration sub trees. E.g. with this method it is
* possible to add parts of another {@code BaseHierarchicalConfiguration}
- * object to this object. (However be aware that a
- * {@code ConfigurationNode} object can only belong to a single
- * configuration. So if nodes from one configuration are directly added to
- * another one using this method, the structure of the source configuration
- * will be broken. In this case you should clone the nodes to be added
- * before calling {@code addNodes()}.) If the passed in key refers to
+ * object to this object. If the passed in key refers to
* an existing and unique node, the new nodes are added to this node.
* Otherwise a new node will be created at the specified position in the
* hierarchy.
@@ -83,11 +85,11 @@ public interface HierarchicalConfigurati
* @param nodes a collection with the {@code Node} objects to be
* added
*/
- void addNodes(String key, Collection<? extends ConfigurationNode> nodes);
+ void addNodes(String key, Collection<? extends T> nodes);
/**
* <p>
- * Returns a hierarchical subnode configuration object that wraps the
+ * Returns a hierarchical sub configuration object that wraps the
* configuration node specified by the given key. This method provides an
* easy means of accessing sub trees of a hierarchical configuration. In the
* returned configuration the sub tree can directly be accessed, it becomes
@@ -101,37 +103,32 @@ public interface HierarchicalConfigurati
* {@code subset()} supports arbitrary subsets of configuration nodes
* while {@code configurationAt()} only returns a single sub tree.
* Please refer to the documentation of the
- * {@code SubnodeConfiguration} class to obtain further information
- * about subnode configurations and when they should be used.
+ * {@link SubnodeConfiguration} class to obtain further information
+ * about sub configurations and when they should be used.
* </p>
* <p>
* With the {@code supportUpdate} flag the behavior of the returned
- * {@code SubnodeConfiguration} regarding updates of its parent
- * configuration can be determined. A subnode configuration operates on the
- * same nodes as its parent, so changes at one configuration are normally
- * directly visible for the other configuration. There are however changes
- * of the parent configuration, which are not recognized by the subnode
- * configuration per default. An example for this is a reload operation (for
- * file-based configurations): Here the complete node set of the parent
- * configuration is replaced, but the subnode configuration still references
- * the old nodes. If such changes should be detected by the subnode
- * configuration, the {@code supportUpdates} flag must be set to
- * <b>true</b>. This causes the subnode configuration to reevaluate the key
- * used for its creation each time it is accessed. This guarantees that the
- * subnode configuration always stays in sync with its key, even if the
- * parent configuration's data significantly changes. If such a change
- * makes the key invalid - because it now no longer points to exactly one
- * node -, the subnode configuration is not reconstructed, but keeps its
- * old data. It is then quasi detached from its parent.
+ * sub configuration regarding updates of its parent
+ * configuration can be determined. If set to <b>false</b>, the configurations
+ * return on independent nodes structures. So changes made on one configuration
+ * cannot be seen by the other one. A value of <b>true</b> in contrast creates
+ * a direct connection between both configurations - they are then using the
+ * same underlying data structures as much as possible. There are however changes
+ * which break this connection; for instance, if the sub tree the sub configuration
+ * belongs to is completely removed from the parent configuration. If such a
+ * change happens, the sub configuration becomes detached from its parent.
+ * It can still be used in a normal way, but changes on it are not reflected
+ * by the parent and vice verse. Also, it is not possible to reattach a once
+ * detached sub configuration.
* </p>
*
* @param key the key that selects the sub tree
- * @param supportUpdates a flag whether the returned subnode configuration
- * should be able to handle updates of its parent
+ * @param supportUpdates a flag whether the returned sub configuration
+ * should be directly connected to its parent
* @return a hierarchical configuration that contains this sub tree
* @see SubnodeConfiguration
*/
- SubnodeConfiguration configurationAt(String key, boolean supportUpdates);
+ HierarchicalConfiguration<T> configurationAt(String key, boolean supportUpdates);
/**
* Returns a hierarchical subnode configuration for the node specified by
@@ -142,17 +139,17 @@ public interface HierarchicalConfigurati
* @return a hierarchical configuration that contains this sub tree
* @see SubnodeConfiguration
*/
- SubnodeConfiguration configurationAt(String key);
+ HierarchicalConfiguration<T> configurationAt(String key);
/**
* Returns a list of sub configurations for all configuration nodes selected
* by the given key. This method will evaluate the passed in key (using the
- * current {@code ExpressionEngine}) and then create a subnode
- * configuration for each returned node (like
- * {@link #configurationAt(String)}}). This is especially
- * useful when dealing with list-like structures. As an example consider the
- * configuration that contains data about database tables and their fields.
- * If you need access to all fields of a certain table, you can simply do
+ * current {@code ExpressionEngine}) and then create a sub configuration for
+ * each returned node (like {@link #configurationAt(String)} ). This is
+ * especially useful when dealing with list-like structures. As an example
+ * consider the configuration that contains data about database tables and
+ * their fields. If you need access to all fields of a certain table, you
+ * can simply do
*
* <pre>
* List fields = config.configurationsAt("tables.table(0).fields.field");
@@ -166,23 +163,61 @@ public interface HierarchicalConfigurati
* ...
* </pre>
*
+ * The configuration objects returned are <strong>not</strong> connected to
+ * the parent configuration.
+ *
+ * @param key the key for selecting the desired nodes
+ * @return a list with hierarchical configuration objects; each
+ * configuration represents one of the nodes selected by the passed
+ * in key
+ */
+ List<HierarchicalConfiguration<T>> configurationsAt(String key);
+
+ /**
+ * Returns a list of sub configurations for all configuration nodes selected
+ * by the given key allowing the caller to specify the
+ * {@code supportUpdates} flag. This method works like
+ * {@link #configurationsAt(String)}, but with the additional boolean
+ * parameter it can be specified whether the returned configurations react
+ * on updates of the parent configuration.
+ *
* @param key the key for selecting the desired nodes
+ * @param supportUpdates a flag whether the returned sub configuration
+ * should be directly connected to its parent
* @return a list with hierarchical configuration objects; each
- * configuration represents one of the nodes selected by the passed in key
+ * configuration represents one of the nodes selected by the passed
+ * in key
+ * @see #configurationsAt(String, boolean)
*/
- List<SubnodeConfiguration> configurationsAt(String key);
+ List<HierarchicalConfiguration<T>> configurationsAt(String key,
+ boolean supportUpdates);
/**
* Returns a list with sub configurations for all child nodes of the node
* selected by the given key. This method works like
* {@link #immutableChildConfigurationsAt(String)}, but returns a list with
- * {@code SubnodeConfiguration} objects.
+ * mutable configuration objects. The configuration objects returned are
+ * <strong>not</strong> connected to the parent configuration.
*
* @param key the key for selecting the desired parent node
- * @return a collection with {@code SubnodeConfiguration} objects for all
+ * @return a collection with {@code HierarchicalConfiguration} objects for all
* child nodes of the selected parent node
*/
- List<SubnodeConfiguration> childConfigurationsAt(String key);
+ List<HierarchicalConfiguration<T>> childConfigurationsAt(String key);
+
+ /**
+ * Returns a list with sub configurations for all child nodes of the node
+ * selected by the given key allowing the caller to specify the
+ * {@code supportUpdates} flag.
+ *
+ * @param key the key for selecting the desired parent node
+ * @param supportUpdates a flag whether the returned sub configuration
+ * should be directly connected to its parent
+ * @return a collection with {@code HierarchicalConfiguration} objects for
+ * all child nodes of the selected parent node
+ */
+ List<HierarchicalConfiguration<T>> childConfigurationsAt(String key,
+ boolean supportUpdates);
/**
* Removes all values of the property with the given name and of keys that
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationXMLReader.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationXMLReader.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationXMLReader.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationXMLReader.java Sun Apr 20 19:32:08 2014
@@ -17,31 +17,38 @@
package org.apache.commons.configuration;
-import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ConfigurationNodeVisitorAdapter;
+import org.apache.commons.configuration.tree.NodeHandler;
+import org.apache.commons.configuration.tree.NodeTreeWalker;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
/**
- * <p>A specialized SAX2 XML parser that "parses" hierarchical
- * configuration objects.</p>
- * <p>This class mimics to be a SAX conform XML parser. Instead of parsing
- * XML documents it processes a {@code Configuration} object and
- * generates SAX events for the single properties defined there. This enables
- * the whole world of XML processing for configuration objects.</p>
- * <p>The {@code HierarchicalConfiguration} object to be parsed can be
- * specified using a constructor or the {@code setConfiguration()} method.
- * This object will be processed by the {@code parse()} methods. Note
- * that these methods ignore their argument.</p>
+ * <p>
+ * A specialized SAX2 XML parser that "parses" hierarchical configuration
+ * objects.
+ * </p>
+ * <p>
+ * This class mimics to be a SAX conform XML parser. Instead of parsing XML
+ * documents it processes a {@code Configuration} object and generates SAX
+ * events for the single properties defined there. This enables the whole world
+ * of XML processing for configuration objects.
+ * </p>
+ * <p>
+ * The {@code HierarchicalConfiguration} object to be parsed can be specified
+ * using a constructor or the {@code setConfiguration()} method. This object
+ * will be processed by the {@code parse()} methods. Note that these methods
+ * ignore their argument.
+ * </p>
*
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
* @version $Id$
+ * @param <T> the type of the nodes supported by this reader
*/
-public class HierarchicalConfigurationXMLReader extends ConfigurationXMLReader
+public class HierarchicalConfigurationXMLReader<T> extends
+ ConfigurationXMLReader
{
- /** Stores the configuration object to be parsed.*/
- private HierarchicalConfiguration configuration;
+ /** Stores the configuration object to be parsed. */
+ private HierarchicalConfiguration<T> configuration;
/**
* Creates a new instance of {@code HierarchicalConfigurationXMLReader}.
@@ -57,7 +64,8 @@ public class HierarchicalConfigurationXM
*
* @param config the configuration object
*/
- public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config)
+ public HierarchicalConfigurationXMLReader(
+ HierarchicalConfiguration<T> config)
{
this();
setConfiguration(config);
@@ -68,7 +76,7 @@ public class HierarchicalConfigurationXM
*
* @return the configuration object to be parsed
*/
- public HierarchicalConfiguration getConfiguration()
+ public HierarchicalConfiguration<T> getConfiguration()
{
return configuration;
}
@@ -78,7 +86,7 @@ public class HierarchicalConfigurationXM
*
* @param config the configuration object to be parsed
*/
- public void setConfiguration(HierarchicalConfiguration config)
+ public void setConfiguration(HierarchicalConfiguration<T> config)
{
configuration = config;
}
@@ -100,50 +108,49 @@ public class HierarchicalConfigurationXM
@Override
protected void processKeys()
{
- getConfiguration().getRootNode().visit(new SAXVisitor());
+ NodeHandler<T> nodeHandler =
+ getConfiguration().getNodeModel().getNodeHandler();
+ NodeTreeWalker.INSTANCE.walkDFS(nodeHandler.getRootNode(),
+ new SAXVisitor(), nodeHandler);
}
/**
- * A specialized visitor class for generating SAX events for a
- * hierarchical node structure.
- *
+ * A specialized visitor class for generating SAX events for a hierarchical
+ * node structure.
*/
- class SAXVisitor extends ConfigurationNodeVisitorAdapter
+ private class SAXVisitor extends ConfigurationNodeVisitorAdapter<T>
{
- /** Constant for the attribute type.*/
+ /** Constant for the attribute type. */
private static final String ATTR_TYPE = "CDATA";
/**
* Visits the specified node after its children have been processed.
*
* @param node the actual node
+ * @param handler the node handler
*/
@Override
- public void visitAfterChildren(ConfigurationNode node)
+ public void visitAfterChildren(T node, NodeHandler<T> handler)
{
- if (!isAttributeNode(node))
- {
- fireElementEnd(nodeName(node));
- }
+ fireElementEnd(nodeName(node, handler));
}
/**
* Visits the specified node.
*
* @param node the actual node
- * @param key the key of this node
+ * @param handler the node handler
*/
@Override
- public void visitBeforeChildren(ConfigurationNode node)
+ public void visitBeforeChildren(T node, NodeHandler<T> handler)
{
- if (!isAttributeNode(node))
- {
- fireElementStart(nodeName(node), fetchAttributes(node));
+ fireElementStart(nodeName(node, handler),
+ fetchAttributes(node, handler));
- if (node.getValue() != null)
- {
- fireCharacters(node.getValue().toString());
- }
+ Object value = handler.getValue(node);
+ if (value != null)
+ {
+ fireCharacters(value.toString());
}
}
@@ -162,19 +169,21 @@ public class HierarchicalConfigurationXM
/**
* Returns an object with all attributes for the specified node.
*
- * @param node the actual node
+ * @param node the current node
+ * @param handler the node handler
* @return an object with all attributes of this node
*/
- protected Attributes fetchAttributes(ConfigurationNode node)
+ protected Attributes fetchAttributes(T node, NodeHandler<T> handler)
{
AttributesImpl attrs = new AttributesImpl();
- for (ConfigurationNode child : node.getAttributes())
+ for (String attr : handler.getAttributes(node))
{
- if (child.getValue() != null)
+ Object value = handler.getAttributeValue(node, attr);
+ if (value != null)
{
- String attr = child.getName();
- attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE, child.getValue().toString());
+ attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE,
+ value.toString());
}
}
@@ -187,24 +196,13 @@ public class HierarchicalConfigurationXM
* will be used.
*
* @param node the node to be checked
+ * @param handler the node handler
* @return the name for this node
*/
- private String nodeName(ConfigurationNode node)
- {
- return (node.getName() == null) ? getRootName() : node.getName();
- }
-
- /**
- * Checks if the specified node is an attribute node. In the node
- * hierarchy attributes are stored as normal child nodes, but with
- * special names.
- *
- * @param node the node to be checked
- * @return a flag if this is an attribute node
- */
- private boolean isAttributeNode(ConfigurationNode node)
+ private String nodeName(T node, NodeHandler<T> handler)
{
- return node.isAttribute();
+ String nodeName = handler.nodeName(node);
+ return (nodeName == null) ? getRootName() : nodeName;
}
}
}
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/INIConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/INIConfiguration.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/INIConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/INIConfiguration.java Sun Apr 20 19:32:08 2014
@@ -21,16 +21,25 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.apache.commons.configuration.convert.ListDelimiterHandler;
import org.apache.commons.configuration.ex.ConfigurationException;
-import org.apache.commons.configuration.tree.ConfigurationNode;
-import org.apache.commons.configuration.tree.ViewNode;
+import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
+import org.apache.commons.configuration.tree.ImmutableNode;
+import org.apache.commons.configuration.tree.InMemoryNodeModel;
+import org.apache.commons.configuration.tree.InMemoryNodeModelSupport;
+import org.apache.commons.configuration.tree.NodeHandler;
+import org.apache.commons.configuration.tree.NodeHandlerDecorator;
+import org.apache.commons.configuration.tree.NodeSelector;
+import org.apache.commons.configuration.tree.TrackedNodeModel;
/**
* <p>
@@ -255,7 +264,7 @@ public class INIConfiguration extends Ba
* @param c the configuration to be copied
* @since 2.0
*/
- public INIConfiguration(HierarchicalConfiguration c)
+ public INIConfiguration(HierarchicalConfiguration<ImmutableNode> c)
{
super(c);
}
@@ -272,23 +281,16 @@ public class INIConfiguration extends Ba
public void write(Writer writer) throws ConfigurationException, IOException
{
PrintWriter out = new PrintWriter(writer);
- Iterator<String> it = getSections().iterator();
- while (it.hasNext())
+ for (String section : getSections())
{
- String section = it.next();
- Configuration subset;
if (section != null)
{
out.print("[");
out.print(section);
out.print("]");
out.println();
- subset = createSubnodeConfiguration(getSectionNode(section), null);
- }
- else
- {
- subset = getSection(null);
}
+ Configuration subset = getSection(section);
Iterator<String> keys = subset.getKeys();
while (keys.hasNext())
@@ -327,7 +329,7 @@ public class INIConfiguration extends Ba
* {@code clear()} method is not called so the configuration read in will
* be merged with the current configuration.
*
- * @param reader The reader to read the configuration from.
+ * @param in the reader to read the configuration from.
* @throws ConfigurationException If an error occurs while reading the
* configuration
* @throws IOException if an I/O error occurs
@@ -336,9 +338,51 @@ public class INIConfiguration extends Ba
public void read(Reader in) throws ConfigurationException, IOException
{
BufferedReader bufferedReader = new BufferedReader(in);
- ConfigurationNode sectionNode = getRootNode();
+ Map<String, ImmutableNode.Builder> sectionBuilders = new LinkedHashMap<String, ImmutableNode.Builder>();
+ ImmutableNode.Builder rootBuilder = new ImmutableNode.Builder();
+
+ createNodeBuilders(bufferedReader, rootBuilder, sectionBuilders);
+ ImmutableNode rootNode = createNewRootNode(rootBuilder, sectionBuilders);
+ addNodes(null, rootNode.getChildren());
+ }
+
+ /**
+ * Creates a new root node from the builders constructed while reading the
+ * configuration file.
+ *
+ * @param rootBuilder the builder for the top-level section
+ * @param sectionBuilders a map storing the section builders
+ * @return the root node of the newly created hierarchy
+ */
+ private static ImmutableNode createNewRootNode(
+ ImmutableNode.Builder rootBuilder,
+ Map<String, ImmutableNode.Builder> sectionBuilders)
+ {
+ for (Map.Entry<String, ImmutableNode.Builder> e : sectionBuilders
+ .entrySet())
+ {
+ rootBuilder.addChild(e.getValue().name(e.getKey()).create());
+ }
+ return rootBuilder.create();
+ }
- String line = bufferedReader.readLine();
+ /**
+ * Reads the content of an INI file from the passed in reader and creates a
+ * structure of builders for constructing the {@code ImmutableNode} objects
+ * representing the data.
+ *
+ * @param in the reader
+ * @param rootBuilder the builder for the top-level section
+ * @param sectionBuilders a map storing the section builders
+ * @throws IOException if an I/O error occurs
+ */
+ private void createNodeBuilders(BufferedReader in,
+ ImmutableNode.Builder rootBuilder,
+ Map<String, ImmutableNode.Builder> sectionBuilders)
+ throws IOException
+ {
+ ImmutableNode.Builder sectionBuilder = rootBuilder;
+ String line = in.readLine();
while (line != null)
{
line = line.trim();
@@ -347,20 +391,23 @@ public class INIConfiguration extends Ba
if (isSectionLine(line))
{
String section = line.substring(1, line.length() - 1);
- sectionNode = getSectionNode(section);
+ sectionBuilder = sectionBuilders.get(section);
+ if (sectionBuilder == null)
+ {
+ sectionBuilder = new ImmutableNode.Builder();
+ sectionBuilders.put(section, sectionBuilder);
+ }
}
else
{
- String key = "";
+ String key;
String value = "";
int index = findSeparator(line);
if (index >= 0)
{
key = line.substring(0, index);
- value =
- parseValue(line.substring(index + 1),
- bufferedReader);
+ value = parseValue(line.substring(index + 1), in);
}
else
{
@@ -372,11 +419,11 @@ public class INIConfiguration extends Ba
// use space for properties with no key
key = " ";
}
- createValueNodes(sectionNode, key, value);
+ createValueNodes(sectionBuilder, key, value);
}
}
- line = bufferedReader.readLine();
+ line = in.readLine();
}
}
@@ -385,20 +432,20 @@ public class INIConfiguration extends Ba
* enabled, the value string is split if possible, and for each single value
* a node is created. Otherwise only a single node is added to the section.
*
- * @param sectionNode the section node new nodes have to be added
+ * @param sectionBuilder the section builder for adding new nodes
* @param key the key
* @param value the value string
*/
- private void createValueNodes(ConfigurationNode sectionNode, String key,
- String value)
+ private void createValueNodes(ImmutableNode.Builder sectionBuilder,
+ String key, String value)
{
- Collection<String> values = getListDelimiterHandler().split(value, false);
+ Collection<String> values =
+ getListDelimiterHandler().split(value, false);
for (String v : values)
{
- ConfigurationNode node = createNode(key);
- node.setValue(v);
- sectionNode.addChild(node);
+ sectionBuilder.addChild(new ImmutableNode.Builder().name(key)
+ .value(v).create());
}
}
@@ -737,12 +784,12 @@ public class INIConfiguration extends Ba
beginRead(false);
try
{
- for (ConfigurationNode node : getRootNode().getChildren())
+ for (ImmutableNode node : getRootNode().getChildren())
{
if (isSectionNode(node))
{
inSection = true;
- sections.add(node.getName());
+ sections.add(node.getNodeName());
}
else
{
@@ -799,50 +846,20 @@ public class INIConfiguration extends Ba
{
try
{
- return configurationAt(name);
+ return (SubnodeConfiguration) configurationAt(name, true);
}
- catch (IllegalArgumentException iex)
+ catch (ConfigurationRuntimeException iex)
{
// the passed in key does not map to exactly one node
// obtain the node for the section, create it on demand
- // (creation of a SubnodeConfiguration has to be synchronized)
- beginWrite(false);
- try
- {
- return createAndInitializeSubnodeConfiguration(
- getSectionNode(name), null, false);
- }
- finally
- {
- endWrite();
- }
+ InMemoryNodeModel parentModel = getSubConfigurationParentModel();
+ NodeSelector selector = parentModel.trackChildNodeWithCreation(null, name, this);
+ return createSubConfigurationForTrackedNode(selector, this);
}
}
}
/**
- * Obtains the node representing the specified section. This method is
- * called while the configuration is loaded. If a node for this section
- * already exists, it is returned. Otherwise a new node is created.
- *
- * @param sectionName the name of the section
- * @return the node for this section
- */
- private ConfigurationNode getSectionNode(String sectionName)
- {
- List<ConfigurationNode> nodes = getRootNode().getChildren(sectionName);
- if (!nodes.isEmpty())
- {
- return nodes.get(0);
- }
-
- ConfigurationNode node = createNode(sectionName);
- markSectionNode(node);
- getRootNode().addChild(node);
- return node;
- }
-
- /**
* Creates a sub configuration for the global section of the represented INI
* configuration.
*
@@ -850,47 +867,136 @@ public class INIConfiguration extends Ba
*/
private SubnodeConfiguration getGlobalSection()
{
- ViewNode parent = new ViewNode();
-
- beginWrite(false);
- try
- {
- for (ConfigurationNode node : getRootNode().getChildren())
- {
- if (!isSectionNode(node))
- {
- parent.addChild(node);
- }
- }
-
- return createAndInitializeSubnodeConfiguration(parent, null, false);
- }
- finally
- {
- endWrite();
- }
+ InMemoryNodeModel parentModel = getSubConfigurationParentModel();
+ NodeSelector selector = new NodeSelector(null); // selects parent
+ parentModel.trackNode(selector, this);
+ GlobalSectionNodeModel model =
+ new GlobalSectionNodeModel(this, selector);
+ SubnodeConfiguration sub = new SubnodeConfiguration(this, model);
+ initSubConfigurationForThisParent(sub);
+ return sub;
}
/**
- * Marks a configuration node as a section node. This means that this node
- * represents a section header. This implementation uses the node's
- * reference property to store a flag.
+ * Checks whether the specified configuration node represents a section.
*
- * @param node the node to be marked
+ * @param node the node in question
+ * @return a flag whether this node represents a section
*/
- private static void markSectionNode(ConfigurationNode node)
+ private static boolean isSectionNode(ImmutableNode node)
{
- node.setReference(Boolean.TRUE);
+ return !node.getChildren().isEmpty();
}
/**
- * Checks whether the specified configuration node represents a section.
- *
- * @param node the node in question
- * @return a flag whether this node represents a section
+ * A specialized node model implementation for the sub configuration
+ * representing the global section of the INI file. This is a regular
+ * {@code TrackedNodeModel} with one exception: The {@code NodeHandler} used
+ * by this model applies a filter on the children of the root node so that
+ * only nodes are visible that are no sub sections.
*/
- private static boolean isSectionNode(ConfigurationNode node)
+ private static class GlobalSectionNodeModel extends TrackedNodeModel
{
- return node.getReference() != null || node.getChildrenCount() > 0;
+ /**
+ * Creates a new instance of {@code GlobalSectionNodeModel} and
+ * initializes it with the given underlying model.
+ *
+ * @param modelSupport the underlying {@code InMemoryNodeModel}
+ * @param selector the {@code NodeSelector}
+ */
+ public GlobalSectionNodeModel(InMemoryNodeModelSupport modelSupport,
+ NodeSelector selector)
+ {
+ super(modelSupport, selector, true);
+ }
+
+ @Override
+ public NodeHandler<ImmutableNode> getNodeHandler()
+ {
+ return new NodeHandlerDecorator<ImmutableNode>()
+ {
+ @Override
+ public List<ImmutableNode> getChildren(ImmutableNode node)
+ {
+ List<ImmutableNode> children = super.getChildren(node);
+ return filterChildrenOfGlobalSection(node, children);
+ }
+
+ @Override
+ public List<ImmutableNode> getChildren(ImmutableNode node,
+ String name)
+ {
+ List<ImmutableNode> children =
+ super.getChildren(node, name);
+ return filterChildrenOfGlobalSection(node, children);
+ }
+
+ @Override
+ public int getChildrenCount(ImmutableNode node, String name)
+ {
+ List<ImmutableNode> children =
+ (name != null) ? super.getChildren(node, name)
+ : super.getChildren(node);
+ return filterChildrenOfGlobalSection(node, children).size();
+ }
+
+ @Override
+ public ImmutableNode getChild(ImmutableNode node, int index)
+ {
+ List<ImmutableNode> children = super.getChildren(node);
+ return filterChildrenOfGlobalSection(node, children).get(
+ index);
+ }
+
+ @Override
+ public int indexOfChild(ImmutableNode parent,
+ ImmutableNode child)
+ {
+ List<ImmutableNode> children = super.getChildren(parent);
+ return filterChildrenOfGlobalSection(parent, children)
+ .indexOf(child);
+ }
+
+ @Override
+ protected NodeHandler<ImmutableNode> getDecoratedNodeHandler()
+ {
+ return GlobalSectionNodeModel.super.getNodeHandler();
+ }
+
+ /**
+ * Filters the child nodes of the global section. This method
+ * checks whether the passed in node is the root node of the
+ * configuration. If so, from the list of children all nodes are
+ * filtered which are section nodes.
+ *
+ * @param node the node in question
+ * @param children the children of this node
+ * @return a list with the filtered children
+ */
+ private List<ImmutableNode> filterChildrenOfGlobalSection(
+ ImmutableNode node, List<ImmutableNode> children)
+ {
+ List<ImmutableNode> filteredList;
+ if (node == getRootNode())
+ {
+ filteredList =
+ new ArrayList<ImmutableNode>(children.size());
+ for (ImmutableNode child : children)
+ {
+ if (!isSectionNode(child))
+ {
+ filteredList.add(child);
+ }
+ }
+ }
+ else
+ {
+ filteredList = children;
+ }
+
+ return filteredList;
+ }
+ };
+ }
}
}
Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigurationWrapper.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigurationWrapper.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigurationWrapper.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigurationWrapper.java Sun Apr 20 19:32:08 2014
@@ -31,8 +31,8 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.configuration.ex.ConfigurationException;
import org.apache.commons.configuration.io.FileBased;
-import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.ImmutableNode;
/**
* Wraps a BaseHierarchicalConfiguration and allows subtrees to be accessed via a configured path with
@@ -50,7 +50,7 @@ public class PatternSubtreeConfiguration
private static final long serialVersionUID = 7456061169617014189L;
/** The wrapped configuration */
- private final HierarchicalConfiguration config;
+ private final HierarchicalConfiguration<ImmutableNode> config;
/** The path to the subtree */
private final String path;
@@ -66,7 +66,8 @@ public class PatternSubtreeConfiguration
* @param config The Configuration to be wrapped.
* @param path The base path pattern.
*/
- public PatternSubtreeConfigurationWrapper(HierarchicalConfiguration config, String path)
+ public PatternSubtreeConfigurationWrapper(
+ HierarchicalConfiguration<ImmutableNode> config, String path)
{
this.config = config;
this.path = path;
@@ -321,13 +322,13 @@ public class PatternSubtreeConfiguration
}
@Override
- public ConfigurationNode getRootNode()
+ public ImmutableNode getRootNode()
{
return getConfig().getRootNode();
}
@Override
- protected void setRootNodeInternal(ConfigurationNode rootNode)
+ protected void setRootNodeInternal(ImmutableNode rootNode)
{
if (init)
{
@@ -359,31 +360,31 @@ public class PatternSubtreeConfiguration
}
@Override
- protected void addNodesInternal(String key, Collection<? extends ConfigurationNode> nodes)
+ protected void addNodesInternal(String key, Collection<? extends ImmutableNode> nodes)
{
getConfig().addNodes(key, nodes);
}
@Override
- public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key, boolean supportUpdates)
{
return config.configurationAt(makePath(key), supportUpdates);
}
@Override
- public SubnodeConfiguration configurationAt(String key)
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key)
{
return config.configurationAt(makePath(key));
}
@Override
- public List<SubnodeConfiguration> configurationsAt(String key)
+ public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(String key)
{
return config.configurationsAt(makePath(key));
}
@Override
- protected List<ConfigurationNode> clearTreeInternal(String key)
+ protected Object clearTreeInternal(String key)
{
config.clearTree(makePath(key));
return Collections.emptyList();
@@ -463,7 +464,7 @@ public class PatternSubtreeConfiguration
private BaseHierarchicalConfiguration getConfig()
{
- return config.configurationAt(makePath());
+ return (BaseHierarchicalConfiguration) config.configurationAt(makePath());
}
private String makePath()