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/13 18:01:21 UTC

svn commit: r1587015 - in /commons/proper/configuration/branches/immutableNodes/src: main/java/org/apache/commons/configuration/CombinedConfiguration.java test/java/org/apache/commons/configuration/TestCombinedConfiguration.java

Author: oheger
Date: Sun Apr 13 16:01:21 2014
New Revision: 1587015

URL: http://svn.apache.org/r1587015
Log:
Reworked CombinedConfiguration to operate on immutable nodes.

The majority of tests is working, but there are still some test failures.

Modified:
    commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java
    commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java

Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java?rev=1587015&r1=1587014&r2=1587015&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java Sun Apr 13 16:01:21 2014
@@ -33,13 +33,11 @@ import org.apache.commons.configuration.
 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.TreeUtils;
 import org.apache.commons.configuration.tree.UnionCombiner;
-import org.apache.commons.configuration.tree.ViewNode;
 
 /**
  * <p>
@@ -172,9 +170,6 @@ import org.apache.commons.configuration.
  * configuration itself). However, this is not enforced.
  * </p>
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @since 1.3
  * @version $Id$
  */
@@ -198,12 +193,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 +212,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 +643,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 +675,6 @@ public class CombinedConfiguration exten
                         .getConfiguration()), cd.getName(), cd.getAt());
             }
 
-            copy.setRootNode(new DefaultConfigurationNode());
             return copy;
         }
         finally
@@ -734,25 +716,27 @@ public class CombinedConfiguration exten
         beginRead(false);
         try
         {
-            List<ConfigurationNode> nodes = fetchNodeList(key);
-            if (nodes.isEmpty())
-            {
-                return null;
-            }
-
-            Iterator<ConfigurationNode> it = nodes.iterator();
-            Configuration source = findSourceConfiguration(it.next());
-            while (it.hasNext())
-            {
-                Configuration src = findSourceConfiguration(it.next());
-                if (src != source)
-                {
-                    throw new IllegalArgumentException("The key " + key
-                            + " is defined by multiple sources!");
-                }
-            }
-
-            return source;
+//            List<ConfigurationNode> nodes = fetchNodeList(key);
+//            if (nodes.isEmpty())
+//            {
+//                return null;
+//            }
+//
+//            Iterator<ConfigurationNode> it = nodes.iterator();
+//            Configuration source = findSourceConfiguration(it.next());
+//            while (it.hasNext())
+//            {
+//                Configuration src = findSourceConfiguration(it.next());
+//                if (src != source)
+//                {
+//                    throw new IllegalArgumentException("The key " + key
+//                            + " is defined by multiple sources!");
+//                }
+//            }
+//
+//            return source;
+            //TODO implementation
+            return null;
         }
         finally
         {
@@ -777,8 +761,8 @@ public class CombinedConfiguration exten
         boolean lockObtained = false;
         do
         {
-            super.beginRead(optimize);
-            if (combinedRoot != null)
+            super.beginRead(false);
+            if (isUpToDate())
             {
                 lockObtained = true;
             }
@@ -808,9 +792,11 @@ public class CombinedConfiguration exten
 
         try
         {
-            if (combinedRoot == null)
+            if (!isUpToDate())
             {
-                combinedRoot = constructCombinedNode();
+                getSubConfigurationParentModel().replaceRoot(
+                        constructCombinedNode(), this);
+                upToDate = true;
             }
         }
         catch (RuntimeException rex)
@@ -821,6 +807,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 +826,7 @@ public class CombinedConfiguration exten
      */
     private void invalidateInternal()
     {
-        combinedRoot = null;
+        upToDate = false;
         fireEvent(EVENT_COMBINED_INVALIDATE, null, null, false);
     }
 
@@ -847,7 +845,7 @@ public class CombinedConfiguration exten
      *
      * @return the combined root node
      */
-    private ConfigurationNode constructCombinedNode()
+    private ImmutableNode constructCombinedNode()
     {
         if (getNumberOfConfigurationsInternal() < 1)
         {
@@ -855,13 +853,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,
@@ -871,7 +869,8 @@ public class CombinedConfiguration exten
             {
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
                 PrintStream stream = new PrintStream(os);
-                TreeUtils.printTree(stream, node);
+                //TODO rework TreeUtils
+                //TreeUtils.printTree(stream, node);
                 getLogger().debug(os.toString());
             }
             return node;
@@ -967,7 +966,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 +1020,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 +1032,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).getModel()
+                                .getInMemoryRepresentation();
                 rootNode = root;
+                return root;
             }
             finally
             {
                 getConfiguration().unlock(LockMode.READ);
             }
-
-            return result;
         }
 
         /**

Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java?rev=1587015&r1=1587014&r2=1587015&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java Sun Apr 13 16:01:21 2014
@@ -45,10 +45,11 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.sync.LockMode;
 import org.apache.commons.configuration.sync.ReadWriteSynchronizer;
 import org.apache.commons.configuration.sync.Synchronizer;
-import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.configuration.tree.DefaultExpressionEngine;
 import org.apache.commons.configuration.tree.DefaultExpressionEngineSymbols;
+import org.apache.commons.configuration.tree.ImmutableNode;
 import org.apache.commons.configuration.tree.NodeCombiner;
+import org.apache.commons.configuration.tree.NodeModel;
 import org.apache.commons.configuration.tree.OverrideCombiner;
 import org.apache.commons.configuration.tree.UnionCombiner;
 import org.junit.Before;
@@ -689,7 +690,7 @@ public class TestCombinedConfiguration
         SynchronizerTestImpl sync = setUpSynchronizerTest();
         config.addConfiguration(new BaseHierarchicalConfiguration());
         sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
-        assertNull("Root node not reset", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -713,7 +714,7 @@ public class TestCombinedConfiguration
         SynchronizerTestImpl sync = setUpSynchronizerTest();
         assertNotNull("No node combiner", config.getNodeCombiner());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -726,7 +727,7 @@ public class TestCombinedConfiguration
         SynchronizerTestImpl sync = setUpSynchronizerTest();
         assertNotNull("No configuration", config.getConfiguration(0));
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -739,7 +740,7 @@ public class TestCombinedConfiguration
         SynchronizerTestImpl sync = setUpSynchronizerTest();
         assertNotNull("No configuration", config.getConfiguration(CHILD1));
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -752,7 +753,7 @@ public class TestCombinedConfiguration
         SynchronizerTestImpl sync = setUpSynchronizerTest();
         assertFalse("No child names", config.getConfigurationNames().isEmpty());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -766,7 +767,17 @@ public class TestCombinedConfiguration
         assertFalse("No child names", config.getConfigurationNameList()
                 .isEmpty());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
+    }
+
+    /**
+     * Helper method for testing that the combined root node has not yet been
+     * constructed.
+     */
+    private void checkCombinedRootNotConstructed()
+    {
+        assertTrue("Root node was constructed", config.getRootNode()
+                .getChildren().isEmpty());
     }
 
     /**
@@ -779,7 +790,7 @@ public class TestCombinedConfiguration
         assertFalse("No child configurations", config.getConfigurations()
                 .isEmpty());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -793,7 +804,7 @@ public class TestCombinedConfiguration
         assertNull("Got a conversion engine",
                 config.getConversionExpressionEngine());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -807,7 +818,7 @@ public class TestCombinedConfiguration
         config.setConversionExpressionEngine(new DefaultExpressionEngine(
                 DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS));
         sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -844,7 +855,7 @@ public class TestCombinedConfiguration
         assertEquals("Wrong number of configurations", 2,
                 config.getNumberOfConfigurations());
         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
-        assertNull("Root node was constructed", config.getRootNode());
+        checkCombinedRootNotConstructed();
     }
 
     /**
@@ -880,10 +891,9 @@ public class TestCombinedConfiguration
                     private static final long serialVersionUID = 1L;
 
                     @Override
-                    public ConfigurationNode getRootNode()
-                    {
+                    public NodeModel<ImmutableNode> getModel() {
                         throw testEx;
-                    };
+                    }
                 };
         config.addConfiguration(childEx);
         try