Bump yangtools to 3.0.0
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 22 Mar 2019 18:32:29 +0000 (19:32 +0100)
committerRobert Varga <nite@hq.sk>
Tue, 16 Apr 2019 08:13:31 +0000 (08:13 +0000)
This is bumps yangtools to 3.0.0, adjusting for changed APIs. The
changes specifically include:

- use ListenerRegistry.getRegistrations() instead of it implementing
  Iterable
- adjust for NormalizedNodeStreamWriter interface change
- remove use of *AttrBuilder, as NormalizedNodes no longer hold
  attributes
- DataTreeCandidateNodes.empty() instead of home-grown implementation
- adjust for DataTreeCandidateNode.getModifiedChild() returning Optional
- use QueuedNotificationManager.BatchedInvoker

Change-Id: Ia30d73ccf6380e3759414b3026b822df0950a481
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.java
java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java
java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java
java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java

index 02bebebd2949d397d9234a27215f1e84de0ce299..cddcd8d17a09e552a7935e6f0f933e3931c973da 100755 (executable)
@@ -44,6 +44,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     private NormalizedNodeWriter normalizedNodeWriter;
     private boolean headerWritten;
     private QName lastLeafSetQName;
+    private boolean inSimple;
 
     AbstractNormalizedNodeDataOutput(final DataOutput output) {
         this.output = Preconditions.checkNotNull(output);
@@ -162,18 +163,15 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void leafNode(final NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
+    public void startLeafNode(final NodeIdentifier name) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.trace("Writing a new leaf node");
+        LOG.trace("Starting a new leaf node");
         startNode(name.getNodeType(), NodeTypes.LEAF_NODE);
-
-        writeObject(value);
+        inSimple = true;
     }
 
     @Override
-    public void startLeafSet(final NodeIdentifier name, final int childSizeHint)
-
-            throws IOException, IllegalArgumentException {
+    public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new leaf set");
 
@@ -182,8 +180,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new ordered leaf set");
 
@@ -192,23 +189,21 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void leafSetEntryNode(final QName name, final Object value) throws IOException, IllegalArgumentException {
-        LOG.trace("Writing a new leaf set entry node");
+    public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
+        LOG.trace("Starting a new leaf set entry node");
 
         output.writeByte(NodeTypes.LEAF_SET_ENTRY_NODE);
 
         // lastLeafSetQName is set if the parent LeafSetNode was previously written. Otherwise this is a
         // stand alone LeafSetEntryNode so write out it's name here.
         if (lastLeafSetQName == null) {
-            writeQName(name);
+            writeQName(name.getNodeType());
         }
-
-        writeObject(value);
+        inSimple = true;
     }
 
     @Override
-    public void startContainerNode(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
 
         LOG.trace("Starting a new container node");
@@ -217,8 +212,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
 
         LOG.trace("Starting a new yang modeled anyXml node");
@@ -227,8 +221,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new unkeyed list");
 
@@ -236,8 +229,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalStateException {
+    public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new unkeyed list item");
 
@@ -245,8 +237,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startMapNode(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new map node");
 
@@ -255,18 +246,16 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
 
     @Override
     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+            throws IOException {
         Preconditions.checkNotNull(identifier, "Node identifier should not be null");
         LOG.trace("Starting a new map entry node");
         startNode(identifier.getNodeType(), NodeTypes.MAP_ENTRY_NODE);
 
         writeKeyValueMap(identifier.getKeyValues());
-
     }
 
     @Override
-    public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new ordered map node");
 
@@ -274,8 +263,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startChoiceNode(final NodeIdentifier name, final int childSizeHint)
-            throws IOException, IllegalArgumentException {
+    public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
         LOG.trace("Starting a new choice node");
 
@@ -283,8 +271,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void startAugmentationNode(final AugmentationIdentifier identifier)
-            throws IOException, IllegalArgumentException {
+    public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
         Preconditions.checkNotNull(identifier, "Node identifier should not be null");
         LOG.trace("Starting a new augmentation node");
 
@@ -293,15 +280,23 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
+    public void startAnyxmlNode(final NodeIdentifier name) throws IOException {
         Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.trace("Writing any xml node");
-
+        LOG.trace("Starting any xml node");
         startNode(name.getNodeType(), NodeTypes.ANY_XML_NODE);
+        inSimple = true;
+    }
 
+    @Override
+    public void scalarValue(final Object value) throws IOException {
+        writeObject(value);
+    }
+
+    @Override
+    public void domSourceValue(final DOMSource value) throws IOException {
         try {
             StreamResult xmlOutput = new StreamResult(new StringWriter());
-            TransformerFactory.newInstance().newTransformer().transform((DOMSource)value, xmlOutput);
+            TransformerFactory.newInstance().newTransformer().transform(value, xmlOutput);
             writeObject(xmlOutput.getWriter().toString());
         } catch (TransformerException | TransformerFactoryConfigurationError e) {
             throw new IOException("Error writing anyXml", e);
@@ -309,10 +304,13 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
     }
 
     @Override
-    public void endNode() throws IOException, IllegalStateException {
+    public void endNode() throws IOException {
         LOG.trace("Ending the node");
-        lastLeafSetQName = null;
-        output.writeByte(NodeTypes.END_NODE);
+        if (!inSimple) {
+            lastLeafSetQName = null;
+            output.writeByte(NodeTypes.END_NODE);
+        }
+        inSimple = false;
     }
 
     @Override
@@ -329,6 +327,7 @@ abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOut
 
     private void startNode(final QName qname, final byte nodeType) throws IOException {
         Preconditions.checkNotNull(qname, "QName of node identifier should not be null.");
+        Preconditions.checkState(!inSimple, "Attempted to start a child in a simple node");
 
         ensureHeaderWritten();
 
index b042963f995accd80687d83d7714c553f185925c..4b845ef787f5a0c341557a7931359af721bbb83b 100755 (executable)
@@ -39,7 +39,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.slf4j.Logger;
@@ -65,11 +65,10 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
 
     private QName lastLeafSetQName;
 
-    private NormalizedNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier,
-                                      Object, LeafNode<Object>> leafBuilder;
+    private NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> leafBuilder;
 
     @SuppressWarnings("rawtypes")
-    private NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder;
+    private NormalizedNodeBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder;
 
     private final StringBuilder reusableStringBuilder = new StringBuilder(50);
 
@@ -149,8 +148,7 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
         }
     }
 
-    private NormalizedNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier,
-                                      Object, LeafNode<Object>> leafBuilder() {
+    private NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> leafBuilder() {
         if (leafBuilder == null) {
             leafBuilder = Builders.leafBuilder();
         }
@@ -159,8 +157,7 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
     }
 
     @SuppressWarnings("rawtypes")
-    private NormalizedNodeAttrBuilder<NodeWithValue, Object,
-                                      LeafSetEntryNode<Object>> leafSetEntryBuilder() {
+    private NormalizedNodeBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder() {
         if (leafSetEntryBuilder == null) {
             leafSetEntryBuilder = Builders.leafSetEntryBuilder();
         }
index 9ce039cd1a4e93260dc646007d6dec6d697eb9f0..03467f39cb37182b368368ac0f618ad50fad2d70 100644 (file)
@@ -10,24 +10,22 @@ package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
+import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import javax.xml.transform.dom.DOMSource;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -75,25 +73,9 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         state = State.OPEN;
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void leafNode(final NodeIdentifier nodeIdentifier, final Object value) {
-        checkNotSealed();
-
-        NormalizedNodeBuilderWrapper parent = stack.peek();
-        LeafNode<Object> leafNode = Builders.leafBuilder().withNodeIdentifier(nodeIdentifier).withValue(value).build();
-        if (parent != null) {
-            if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
-                parent.builder().addChild(leafNode);
-            }
-        } else {
-            // If there's no parent node then this is a stand alone LeafNode.
-            if (nodePathSchemaNode != null) {
-                this.normalizedNode = leafNode;
-            }
-
-            state = State.CLOSED;
-        }
+    public void startLeafNode(final NodeIdentifier name) {
+        addBuilder(Builders.leafBuilder().withNodeIdentifier(name), name);
     }
 
     @Override
@@ -106,28 +88,9 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void leafSetEntryNode(final QName name, final Object value) {
-        checkNotSealed();
-
-        NormalizedNodeBuilderWrapper parent = stack.peek();
-        if (parent != null) {
-            if (hasValidSchema(name, parent)) {
-                parent.builder().addChild(Builders.leafSetEntryBuilder().withValue(value)
-                        .withNodeIdentifier(new NodeWithValue<>(parent.nodeType(), value))
-                        .build());
-            }
-        } else {
-            // If there's no parent LeafSetNode then this is a stand alone
-            // LeafSetEntryNode.
-            if (nodePathSchemaNode != null) {
-                this.normalizedNode = Builders.leafSetEntryBuilder().withValue(value).withNodeIdentifier(
-                        new NodeWithValue<>(name, value)).build();
-            }
-
-            state = State.CLOSED;
-        }
+    public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
+        addBuilder(Builders.leafSetEntryBuilder().withNodeIdentifier(name), name);
     }
 
     @Override
@@ -176,29 +139,21 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void anyxmlNode(final NodeIdentifier nodeIdentifier, final Object value) {
-        checkNotSealed();
+    public void startAnyxmlNode(final NodeIdentifier name) {
+        addBuilder(Builders.anyXmlBuilder().withNodeIdentifier(name), name);
+    }
 
-        NormalizedNodeBuilderWrapper parent = stack.peek();
-        AnyXmlNode anyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).withValue((DOMSource) value)
-                .build();
-        if (parent != null) {
-            if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
-                parent.builder().addChild(anyXmlNode);
-            }
-        } else {
-            // If there's no parent node then this is a stand alone AnyXmlNode.
-            if (nodePathSchemaNode != null) {
-                this.normalizedNode = anyXmlNode;
-            }
+    @Override
+    public void domSourceValue(final DOMSource value) {
+        setValue(value);
+    }
 
-            state = State.CLOSED;
-        }
+    @Override
+    public void scalarValue(final Object value) {
+        setValue(value);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public void endNode() {
         checkNotSealed();
@@ -219,13 +174,13 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
             return;
         }
 
-        final NormalizedNode<?, ?> newNode = child.builder().build();
+        final NormalizedNode<?, ?> newNode = child.build();
         final NormalizedNodeBuilderWrapper parent = stack.peek();
         if (parent == null) {
             normalizedNode = newNode;
             state = State.CLOSED;
         } else {
-            parent.builder().addChild(newNode);
+            parent.addChild(newNode);
         }
     }
 
@@ -255,25 +210,21 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         checkState(state == State.OPEN, "Illegal operation in state %s", state);
     }
 
-    private static boolean hasValidSchema(final QName name, final NormalizedNodeBuilderWrapper parent) {
-        final DataSchemaContextNode<?> parentSchema = parent.getSchema();
-        final boolean valid = parentSchema != null && parentSchema.getChild(name) != null;
-        if (!valid) {
-            LOG.debug("Schema not found for {}", name);
-        }
-
-        return valid;
+    private void setValue(final Object value) {
+        checkNotSealed();
+        final NormalizedNodeBuilderWrapper current = stack.peek();
+        checkState(current != null, "Attempted to set value %s while no node is open", value);
+        current.setValue(value);
     }
 
-    private NormalizedNodeBuilderWrapper addBuilder(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
+    private <T extends NormalizedNodeBuilder<?, ?, ?>> NormalizedNodeBuilderWrapper addBuilder(final T builder,
             final PathArgument identifier) {
         checkNotSealed();
 
         final DataSchemaContextNode<?> schemaNode;
         final NormalizedNodeBuilderWrapper parent = stack.peek();
         if (parent != null) {
-            final DataSchemaContextNode<?> parentSchema = parent.getSchema();
-            schemaNode = parentSchema == null ? null : parentSchema.getChild(identifier);
+            schemaNode = parent.childSchema(identifier);
         } else {
             schemaNode = nodePathSchemaNode;
         }
index 726f69effb2488a74c6c9b1c31eb8ecf38a85251..385376c5277ac7cc3fd29ded6bdaf85293b18fbc 100644 (file)
@@ -7,35 +7,29 @@
  */
 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
 
+import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 
 final class NormalizedNodeBuilderWrapper {
-    private final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder;
+    @SuppressWarnings("rawtypes")
+    private final NormalizedNodeBuilder builder;
     private final PathArgument identifier;
     private final DataSchemaContextNode<?> schemaNode;
 
-    NormalizedNodeBuilderWrapper(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
+    NormalizedNodeBuilderWrapper(final NormalizedNodeBuilder<?, ?, ?> builder,
             final PathArgument identifier, final @Nullable DataSchemaContextNode<?> schemaNode) {
         this.builder = requireNonNull(builder);
         this.identifier = requireNonNull(identifier);
         this.schemaNode = schemaNode;
     }
 
-    @SuppressWarnings("rawtypes")
-    NormalizedNodeContainerBuilder builder() {
-        return builder;
-    }
-
-    QName nodeType() {
-        return identifier.getNodeType();
-    }
-
     PathArgument identifier() {
         return identifier;
     }
@@ -43,4 +37,32 @@ final class NormalizedNodeBuilderWrapper {
     @Nullable DataSchemaContextNode<?> getSchema() {
         return schemaNode;
     }
+
+    @Nullable DataSchemaContextNode<?> childSchema(final PathArgument child) {
+        if (schemaNode == null) {
+            return null;
+        }
+
+        checkState(builder instanceof NormalizedNodeContainerBuilder,
+            "Attempted to lookup child %s in non-container %s", schemaNode);
+        return schemaNode.getChild(child);
+    }
+
+    NormalizedNode<?, ?> build() {
+        return builder.build();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    void addChild(final NormalizedNode<?, ?> child) {
+        checkState(builder instanceof NormalizedNodeContainerBuilder,
+            "Attempted to add child %s to non-container builder %s", child, builder);
+        ((NormalizedNodeContainerBuilder) builder).addChild(child);
+    }
+
+    @SuppressWarnings("unchecked")
+    void setValue(final Object value) {
+        checkState(!(builder instanceof NormalizedNodeContainerBuilder),
+            "Attempted to set value %s on container builder %s", value, builder);
+        builder.withValue(value);
+    }
 }