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/19 20:01:28 UTC

svn commit: r1588681 - /commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java

Author: oheger
Date: Sat Apr 19 18:01:27 2014
New Revision: 1588681

URL: http://svn.apache.org/r1588681
Log:
Reworked XMLPropertyListConfiguration to be compatible with immutable nodes.

Modified:
    commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java

Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java?rev=1588681&r1=1588680&r2=1588681&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java Sat Apr 19 18:01:27 2014
@@ -17,6 +17,8 @@
 
 package org.apache.commons.configuration.plist;
 
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.Writer;
@@ -31,13 +33,11 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.TimeZone;
 
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.configuration.BaseHierarchicalConfiguration;
 import org.apache.commons.configuration.Configuration;
@@ -47,8 +47,8 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.ex.ConfigurationException;
 import org.apache.commons.configuration.io.FileLocator;
 import org.apache.commons.configuration.io.FileLocatorAware;
-import org.apache.commons.configuration.tree.ConfigurationNode;
-import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.configuration.tree.ImmutableNode;
+import org.apache.commons.configuration.tree.InMemoryNodeModel;
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.xml.sax.Attributes;
@@ -144,7 +144,6 @@ public class XMLPropertyListConfiguratio
      */
     public XMLPropertyListConfiguration()
     {
-        initRoot();
     }
 
     /**
@@ -154,11 +153,22 @@ public class XMLPropertyListConfiguratio
      * @param configuration the configuration to copy
      * @since 1.4
      */
-    public XMLPropertyListConfiguration(HierarchicalConfiguration configuration)
+    public XMLPropertyListConfiguration(HierarchicalConfiguration<ImmutableNode> configuration)
     {
         super(configuration);
     }
 
+    /**
+     * Creates a new instance of {@code XMLPropertyConfiguration} with the given
+     * root node.
+     *
+     * @param root the root node
+     */
+    XMLPropertyListConfiguration(ImmutableNode root)
+    {
+        super(new InMemoryNodeModel(root));
+    }
+
     @Override
     protected void setPropertyInternal(String key, Object value)
     {
@@ -210,26 +220,19 @@ public class XMLPropertyListConfiguratio
     @Override
     public void read(Reader in) throws ConfigurationException
     {
-        // We have to make sure that the root node is actually a PListNode.
-        // If this object was not created using the standard constructor, the
-        // root node is a plain Node.
-        if (!(getRootNode() instanceof PListNode))
-        {
-            initRoot();
-        }
-
         // set up the DTD validation
         EntityResolver resolver = new EntityResolver()
         {
             @Override
             public InputSource resolveEntity(String publicId, String systemId)
             {
-                return new InputSource(getClass().getClassLoader().getResourceAsStream("PropertyList-1.0.dtd"));
+                return new InputSource(getClass().getClassLoader()
+                        .getResourceAsStream("PropertyList-1.0.dtd"));
             }
         };
 
         // parse the file
-        XMLPropertyListHandler handler = new XMLPropertyListHandler(getRootNode());
+        XMLPropertyListHandler handler = new XMLPropertyListHandler();
         try
         {
             SAXParserFactory factory = SAXParserFactory.newInstance();
@@ -239,10 +242,14 @@ public class XMLPropertyListConfiguratio
             parser.getXMLReader().setEntityResolver(resolver);
             parser.getXMLReader().setContentHandler(handler);
             parser.getXMLReader().parse(new InputSource(in));
+
+            getNodeModel().mergeRoot(handler.getResultBuilder().createNode(),
+                    null, null, null, this);
         }
         catch (Exception e)
         {
-            throw new ConfigurationException("Unable to parse the configuration file", e);
+            throw new ConfigurationException(
+                    "Unable to parse the configuration file", e);
         }
     }
 
@@ -272,24 +279,24 @@ public class XMLPropertyListConfiguratio
     /**
      * Append a node to the writer, indented according to a specific level.
      */
-    private void printNode(PrintWriter out, int indentLevel, ConfigurationNode node)
+    private void printNode(PrintWriter out, int indentLevel, ImmutableNode node)
     {
         String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);
 
-        if (node.getName() != null)
+        if (node.getNodeName() != null)
         {
-            out.println(padding + "<key>" + StringEscapeUtils.escapeXml(node.getName()) + "</key>");
+            out.println(padding + "<key>" + StringEscapeUtils.escapeXml(node.getNodeName()) + "</key>");
         }
 
-        List<ConfigurationNode> children = node.getChildren();
+        List<ImmutableNode> children = node.getChildren();
         if (!children.isEmpty())
         {
             out.println(padding + "<dict>");
 
-            Iterator<ConfigurationNode> it = children.iterator();
+            Iterator<ImmutableNode> it = children.iterator();
             while (it.hasNext())
             {
-                ConfigurationNode child = it.next();
+                ImmutableNode child = it.next();
                 printNode(out, indentLevel + 1, child);
 
                 if (it.hasNext())
@@ -320,9 +327,9 @@ public class XMLPropertyListConfiguratio
 
         if (value instanceof Date)
         {
-            synchronized (PListNode.FORMAT)
+            synchronized (PListNodeBuilder.FORMAT)
             {
-                out.println(padding + "<date>" + PListNode.FORMAT.format((Date) value) + "</date>");
+                out.println(padding + "<date>" + PListNodeBuilder.FORMAT.format((Date) value) + "</date>");
             }
         }
         else if (value instanceof Calendar)
@@ -354,16 +361,20 @@ public class XMLPropertyListConfiguratio
         else if (value instanceof List)
         {
             out.println(padding + "<array>");
-            Iterator<?> it = ((List<?>) value).iterator();
-            while (it.hasNext())
+            for (Object o : (List<?>) value)
             {
-                printValue(out, indentLevel + 1, it.next());
+                printValue(out, indentLevel + 1, o);
             }
             out.println(padding + "</array>");
         }
         else if (value instanceof HierarchicalConfiguration)
         {
-            printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRootNode());
+            // This is safe because we have created this configuration
+            @SuppressWarnings("unchecked")
+            HierarchicalConfiguration<ImmutableNode> config =
+                    (HierarchicalConfiguration<ImmutableNode>) value;
+            printNode(out, indentLevel, config.getNodeModel().getNodeHandler()
+                    .getRootNode());
         }
         else if (value instanceof Configuration)
         {
@@ -376,8 +387,9 @@ public class XMLPropertyListConfiguratio
             {
                 // create a node for each property
                 String key = it.next();
-                ConfigurationNode node = new DefaultConfigurationNode(key);
-                node.setValue(config.getProperty(key));
+                ImmutableNode node =
+                        new ImmutableNode.Builder().name(key)
+                                .value(config.getProperty(key)).create();
 
                 // print the node
                 printNode(out, indentLevel + 1, node);
@@ -411,14 +423,6 @@ public class XMLPropertyListConfiguratio
     }
 
     /**
-     * Helper method for initializing the configuration's root node.
-     */
-    private void initRoot()
-    {
-        setRootNode(new PListNode());
-    }
-
-    /**
      * Transform a map of arbitrary types into a map with string keys and object
      * values. All keys of the source map which are not of type String are
      * dropped.
@@ -448,17 +452,31 @@ public class XMLPropertyListConfiguratio
         private final StringBuilder buffer = new StringBuilder();
 
         /** The stack of configuration nodes */
-        private final List<ConfigurationNode> stack = new ArrayList<ConfigurationNode>();
+        private final List<PListNodeBuilder> stack = new ArrayList<PListNodeBuilder>();
+
+        /** The builder for the resulting node. */
+        private final PListNodeBuilder resultBuilder;
 
-        public XMLPropertyListHandler(ConfigurationNode root)
+        public XMLPropertyListHandler()
+        {
+            resultBuilder = new PListNodeBuilder();
+            push(resultBuilder);
+        }
+
+        /**
+         * Returns the builder for the result node.
+         *
+         * @return the result node builder
+         */
+        public PListNodeBuilder getResultBuilder()
         {
-            push(root);
+            return resultBuilder;
         }
 
         /**
          * Return the node on the top of the stack.
          */
-        private ConfigurationNode peek()
+        private PListNodeBuilder peek()
         {
             if (!stack.isEmpty())
             {
@@ -473,7 +491,7 @@ public class XMLPropertyListConfiguratio
         /**
          * Remove and return the node on the top of the stack.
          */
-        private ConfigurationNode pop()
+        private PListNodeBuilder pop()
         {
             if (!stack.isEmpty())
             {
@@ -488,7 +506,7 @@ public class XMLPropertyListConfiguratio
         /**
          * Put a node on the top of the stack.
          */
-        private void push(ConfigurationNode node)
+        private void push(PListNodeBuilder node)
         {
             stack.add(node);
         }
@@ -498,21 +516,14 @@ public class XMLPropertyListConfiguratio
         {
             if ("array".equals(qName))
             {
-                push(new ArrayNode());
+                push(new ArrayNodeBuilder());
             }
             else if ("dict".equals(qName))
             {
-                if (peek() instanceof ArrayNode)
+                if (peek() instanceof ArrayNodeBuilder)
                 {
-                    // create the configuration
-                    XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
-
-                    // add it to the ArrayNode
-                    ArrayNode node = (ArrayNode) peek();
-                    node.addValue(config);
-
-                    // push the root on the stack
-                    push(config.getRootNode());
+                    // push the new root builder on the stack
+                    push(new PListNodeBuilder());
                 }
             }
         }
@@ -523,7 +534,7 @@ public class XMLPropertyListConfiguratio
             if ("key".equals(qName))
             {
                 // create a new node, link it to its parent and push it on the stack
-                PListNode node = new PListNode();
+                PListNodeBuilder node = new PListNodeBuilder();
                 node.setName(buffer.toString());
                 peek().addChild(node);
                 push(node);
@@ -531,39 +542,48 @@ public class XMLPropertyListConfiguratio
             else if ("dict".equals(qName))
             {
                 // remove the root of the XMLPropertyListConfiguration previously pushed on the stack
-                pop();
+                PListNodeBuilder builder = pop();
+                if (peek() instanceof ArrayNodeBuilder)
+                {
+                    // create the configuration
+                    XMLPropertyListConfiguration config = new XMLPropertyListConfiguration(builder.createNode());
+
+                    // add it to the ArrayNodeBuilder
+                    ArrayNodeBuilder node = (ArrayNodeBuilder) peek();
+                    node.addValue(config);
+                }
             }
             else
             {
                 if ("string".equals(qName))
                 {
-                    ((PListNode) peek()).addValue(buffer.toString());
+                    peek().addValue(buffer.toString());
                 }
                 else if ("integer".equals(qName))
                 {
-                    ((PListNode) peek()).addIntegerValue(buffer.toString());
+                    peek().addIntegerValue(buffer.toString());
                 }
                 else if ("real".equals(qName))
                 {
-                    ((PListNode) peek()).addRealValue(buffer.toString());
+                    peek().addRealValue(buffer.toString());
                 }
                 else if ("true".equals(qName))
                 {
-                    ((PListNode) peek()).addTrueValue();
+                    peek().addTrueValue();
                 }
                 else if ("false".equals(qName))
                 {
-                    ((PListNode) peek()).addFalseValue();
+                    peek().addFalseValue();
                 }
                 else if ("data".equals(qName))
                 {
-                    ((PListNode) peek()).addDataValue(buffer.toString());
+                    peek().addDataValue(buffer.toString());
                 }
                 else if ("date".equals(qName))
                 {
                     try
                     {
-                        ((PListNode) peek()).addDateValue(buffer.toString());
+                        peek().addDateValue(buffer.toString());
                     }
                     catch (IllegalArgumentException iex)
                     {
@@ -573,13 +593,13 @@ public class XMLPropertyListConfiguratio
                 }
                 else if ("array".equals(qName))
                 {
-                    ArrayNode array = (ArrayNode) pop();
-                    ((PListNode) peek()).addList(array);
+                    ArrayNodeBuilder array = (ArrayNodeBuilder) pop();
+                    peek().addList(array);
                 }
 
                 // remove the plist node on the stack once the value has been parsed,
                 // array nodes remains on the stack for the next values in the list
-                if (!(peek() instanceof ArrayNode))
+                if (!(peek() instanceof ArrayNodeBuilder))
                 {
                     pop();
                 }
@@ -596,18 +616,12 @@ public class XMLPropertyListConfiguratio
     }
 
     /**
-     * Node extension with addXXX methods to parse the typed data passed by the SAX handler.
-     * <b>Do not use this class !</b> It is used internally by XMLPropertyConfiguration
-     * to parse the configuration file, it may be removed at any moment in the future.
+     * A specialized builder class with addXXX methods to parse the typed data passed by the SAX handler.
+     * It is used for creating the nodes of the configuration.
      */
-    public static class PListNode extends DefaultConfigurationNode
+    private static class PListNodeBuilder
     {
         /**
-         * The serial version UID.
-         */
-        private static final long serialVersionUID = -7614060264754798317L;
-
-        /**
          * The MacOS FORMAT of dates in plist files. Note: Because
          * {@code SimpleDateFormat} is not thread-safe, each access has to be
          * synchronized.
@@ -625,33 +639,43 @@ public class XMLPropertyListConfiguratio
          */
         private static final DateFormat GNUSTEP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
 
+        /** A collection with child builders of this builder. */
+        private final Collection<PListNodeBuilder> childBuilders =
+                new LinkedList<PListNodeBuilder>();
+
+        /** The name of the represented node. */
+        private String name;
+
+        /** The current value of the represented node. */
+        private Object value;
+
         /**
          * Update the value of the node. If the existing value is null, it's
          * replaced with the new value. If the existing value is a list, the
          * specified value is appended to the list. If the existing value is
          * not null, a list with the two values is built.
          *
-         * @param value the value to be added
+         * @param v the value to be added
          */
-        public void addValue(Object value)
+        public void addValue(Object v)
         {
-            if (getValue() == null)
+            if (value == null)
             {
-                setValue(value);
+                value = v;
             }
-            else if (getValue() instanceof Collection)
+            else if (value instanceof Collection)
             {
                 // This is safe because we create the collections ourselves
                 @SuppressWarnings("unchecked")
-                Collection<Object> collection = (Collection<Object>) getValue();
-                collection.add(value);
+                Collection<Object> collection = (Collection<Object>) value;
+                collection.add(v);
             }
             else
             {
                 List<Object> list = new ArrayList<Object>();
-                list.add(getValue());
                 list.add(value);
-                setValue(list);
+                list.add(v);
+                value = list;
             }
         }
 
@@ -741,9 +765,56 @@ public class XMLPropertyListConfiguratio
          *
          * @param node the node whose value will be added to the current node value
          */
-        public void addList(ArrayNode node)
+        public void addList(ArrayNodeBuilder node)
         {
-            addValue(node.getValue());
+            addValue(node.getNodeValue());
+        }
+
+        /**
+         * Sets the name of the represented node.
+         *
+         * @param nodeName the node name
+         */
+        public void setName(String nodeName)
+        {
+            name = nodeName;
+        }
+
+        /**
+         * Adds the given child builder to this builder.
+         *
+         * @param child the child builder to be added
+         */
+        public void addChild(PListNodeBuilder child)
+        {
+            childBuilders.add(child);
+        }
+
+        /**
+         * Creates the configuration node defined by this builder.
+         *
+         * @return the newly created configuration node
+         */
+        public ImmutableNode createNode()
+        {
+            ImmutableNode.Builder nodeBuilder =
+                    new ImmutableNode.Builder(childBuilders.size());
+            for (PListNodeBuilder child : childBuilders)
+            {
+                nodeBuilder.addChild(child.createNode());
+            }
+            return nodeBuilder.name(name).value(getNodeValue()).create();
+        }
+
+        /**
+         * Returns the final value for the node to be created. This method is
+         * called when the represented configuration node is actually created.
+         *
+         * @return the value of the resulting configuration node
+         */
+        protected Object getNodeValue()
+        {
+            return value;
         }
     }
 
@@ -752,13 +823,8 @@ public class XMLPropertyListConfiguratio
      * It is used internally by XMLPropertyConfiguration to parse the
      * configuration file, it may be removed at any moment in the future.
      */
-    public static class ArrayNode extends PListNode
+    private static class ArrayNodeBuilder extends PListNodeBuilder
     {
-        /**
-         * The serial version UID.
-         */
-        private static final long serialVersionUID = 5586544306664205835L;
-
         /** The list of values in the array. */
         private final List<Object> list = new ArrayList<Object>();
 
@@ -779,7 +845,7 @@ public class XMLPropertyListConfiguratio
          * @return the {@link List} of values
          */
         @Override
-        public Object getValue()
+        protected Object getNodeValue()
         {
             return list;
         }