Add MultipleEntryDataWithSchema interface
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / CompositeNodeDataWithSchema.java
index 93b87bb20b2c5f8d84e41d78774d8d30b980ef79..8b79165cf9afe5f028def1aa8824b545c13258f4 100644 (file)
@@ -7,11 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.util;
 
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -19,43 +17,56 @@ import java.util.Collection;
 import java.util.Deque;
 import java.util.List;
 import java.util.Map.Entry;
-import javax.annotation.Nonnull;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyxmlSchemaNode;
+import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
 
 /**
- * A node which is composed of multiple simpler nodes.
+ * Utility class used for tracking parser state as needed by a StAX-like parser.
+ * This class is to be used only by respective XML and JSON parsers in yang-data-codec-xml and yang-data-codec-gson.
+ *
+ * <p>
+ * Represents a node which is composed of multiple simpler nodes.
  */
-public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
-
+public class CompositeNodeDataWithSchema<T extends DataSchemaNode> extends AbstractNodeDataWithSchema<T> {
     /**
-     * nodes which were added to schema via augmentation and are present in data input
+     * nodes which were added to schema via augmentation and are present in data input.
      */
-    private final Multimap<AugmentationSchema, AbstractNodeDataWithSchema> augmentationsToChild = ArrayListMultimap.create();
+    private final Multimap<AugmentationSchemaNode, AbstractNodeDataWithSchema<?>> augmentationsToChild =
+        ArrayListMultimap.create();
 
     /**
      * remaining data nodes (which aren't added via augment). Every of one them should have the same QName.
      */
-    private final List<AbstractNodeDataWithSchema> children = new ArrayList<>();
+    private final List<AbstractNodeDataWithSchema<?>> children = new ArrayList<>();
 
-    public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
+    public CompositeNodeDataWithSchema(final T schema) {
         super(schema);
     }
 
-    public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
-        Preconditions.checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
+    private AbstractNodeDataWithSchema<?> addChild(final DataSchemaNode schema) {
+        AbstractNodeDataWithSchema<?> newChild = addSimpleChild(schema);
+        return newChild == null ? addCompositeChild(schema) : newChild;
+    }
+
+    @Deprecated
+    public void addChild(final AbstractNodeDataWithSchema<?> newChild) {
+        children.add(newChild);
+    }
+
+    public AbstractNodeDataWithSchema<?> addChild(final Deque<DataSchemaNode> schemas) {
+        checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
 
         // Pop the first node...
         final DataSchemaNode schema = schemas.pop();
@@ -66,29 +77,29 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
 
         // The choice/case mess, reuse what we already popped
         final DataSchemaNode choiceCandidate = schema;
-        Preconditions.checkArgument(choiceCandidate instanceof ChoiceSchemaNode,
-            "Expected node of type ChoiceNode but was %s", choiceCandidate.getClass().getSimpleName());
+        checkArgument(choiceCandidate instanceof ChoiceSchemaNode, "Expected node of type ChoiceNode but was %s",
+            choiceCandidate.getClass());
         final ChoiceSchemaNode choiceNode = (ChoiceSchemaNode) choiceCandidate;
 
         final DataSchemaNode caseCandidate = schemas.pop();
-        Preconditions.checkArgument(caseCandidate instanceof ChoiceCaseNode,
-            "Expected node of type ChoiceCaseNode but was %s", caseCandidate.getClass().getSimpleName());
-        final ChoiceCaseNode caseNode = (ChoiceCaseNode) caseCandidate;
+        checkArgument(caseCandidate instanceof CaseSchemaNode, "Expected node of type ChoiceCaseNode but was %s",
+            caseCandidate.getClass());
+        final CaseSchemaNode caseNode = (CaseSchemaNode) caseCandidate;
 
-        AugmentationSchema augSchema = null;
+        AugmentationSchemaNode augSchema = null;
         if (choiceCandidate.isAugmenting()) {
             augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
         }
 
         // looking for existing choice
-        final Collection<AbstractNodeDataWithSchema> childNodes;
+        final Collection<AbstractNodeDataWithSchema<?>> childNodes;
         if (augSchema != null) {
             childNodes = augmentationsToChild.get(augSchema);
         } else {
             childNodes = children;
         }
 
-        CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
+        CompositeNodeDataWithSchema<?> caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
         if (caseNodeDataWithSchema == null) {
             ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
             childNodes.add(choiceNodeDataWithSchema);
@@ -98,21 +109,23 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         return caseNodeDataWithSchema.addChild(schemas);
     }
 
-    private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
-        SimpleNodeDataWithSchema newChild = null;
+    private AbstractNodeDataWithSchema<?> addSimpleChild(final DataSchemaNode schema) {
+        SimpleNodeDataWithSchema<?> newChild = null;
         if (schema instanceof LeafSchemaNode) {
-            newChild = new LeafNodeDataWithSchema(schema);
-        } else if (schema instanceof AnyXmlSchemaNode) {
-            // YangModeledAnyXmlSchemaNode is handled by addCompositeChild method.
-            if (schema instanceof YangModeledAnyXmlSchemaNode) {
+            newChild = new LeafNodeDataWithSchema((LeafSchemaNode) schema);
+        } else if (schema instanceof AnyxmlSchemaNode) {
+            // YangModeledAnyxmlSchemaNode is handled by addCompositeChild method.
+            if (schema instanceof YangModeledAnyxmlSchemaNode) {
                 return null;
             }
-            newChild = new AnyXmlNodeDataWithSchema(schema);
+            newChild = new AnyXmlNodeDataWithSchema((AnyxmlSchemaNode) schema);
+        } else if (schema instanceof AnydataSchemaNode) {
+            newChild = new AnydataNodeDataWithSchema((AnydataSchemaNode) schema);
         } else {
             return null;
         }
 
-        AugmentationSchema augSchema = null;
+        AugmentationSchemaNode augSchema = null;
         if (schema.isAugmenting()) {
             augSchema = findCorrespondingAugment(getSchema(), schema);
         }
@@ -124,17 +137,18 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         return newChild;
     }
 
-    private static CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema> childNodes,
+    private static CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema<?>> childNodes,
             final DataSchemaNode choiceCandidate, final DataSchemaNode caseCandidate) {
         if (childNodes != null) {
-            for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
+            for (AbstractNodeDataWithSchema<?> nodeDataWithSchema : childNodes) {
                 if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
                         && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
                     CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
 
-                    Preconditions.checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
-                        "Data from case %s are specified but other data from case %s were specified earlier. Data aren't from the same case.",
-                        caseCandidate.getQName(), casePrevious.getSchema().getQName());
+                    checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
+                        "Data from case %s are specified but other data from case %s were specified earlier."
+                        + " Data aren't from the same case.", caseCandidate.getQName(),
+                        casePrevious.getSchema().getQName());
 
                     return casePrevious;
                 }
@@ -143,27 +157,27 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         return null;
     }
 
-    AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
-        final CompositeNodeDataWithSchema newChild;
+    AbstractNodeDataWithSchema<?> addCompositeChild(final DataSchemaNode schema) {
+        final CompositeNodeDataWithSchema<?> newChild;
 
         if (schema instanceof ListSchemaNode) {
-            newChild = new ListNodeDataWithSchema(schema);
+            newChild = new ListNodeDataWithSchema((ListSchemaNode) schema);
         } else if (schema instanceof LeafListSchemaNode) {
-            newChild = new LeafListNodeDataWithSchema(schema);
+            newChild = new LeafListNodeDataWithSchema((LeafListSchemaNode) schema);
         } else if (schema instanceof ContainerSchemaNode) {
-            newChild = new ContainerNodeDataWithSchema(schema);
-        } else if (schema instanceof YangModeledAnyXmlSchemaNode) {
-            newChild = new YangModeledAnyXmlNodeDataWithSchema((YangModeledAnyXmlSchemaNode)schema);
+            newChild = new ContainerNodeDataWithSchema((ContainerSchemaNode) schema);
+        } else if (schema instanceof YangModeledAnyxmlSchemaNode) {
+            newChild = new YangModeledAnyXmlNodeDataWithSchema((YangModeledAnyxmlSchemaNode)schema);
         } else {
-            newChild = new CompositeNodeDataWithSchema(schema);
+            newChild = new CompositeNodeDataWithSchema<>(schema);
         }
 
         addCompositeChild(newChild);
         return newChild;
     }
 
-    void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
-        AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
+    void addCompositeChild(final CompositeNodeDataWithSchema<?> newChild) {
+        AugmentationSchemaNode augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
         if (augSchema != null) {
             augmentationsToChild.put(augSchema, newChild);
         } else {
@@ -171,15 +185,6 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         }
     }
 
-    private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
-        AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
-        return newChild == null ? addCompositeChild(schema) : newChild;
-    }
-
-    public void addChild(final AbstractNodeDataWithSchema newChild) {
-        children.add(newChild);
-    }
-
     /**
      * Return a hint about how may children we are going to generate.
      * @return Size of currently-present node list.
@@ -189,18 +194,21 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     }
 
     @Override
-    public void write(final SchemaAwareNormalizedNodeStreamWriter writer) throws IOException {
-        for (AbstractNodeDataWithSchema child : children) {
-            child.write(writer);
+    public void write(final NormalizedNodeStreamWriter writer, final StreamWriterMetadataExtension metaWriter)
+            throws IOException {
+        for (AbstractNodeDataWithSchema<?> child : children) {
+            child.write(writer, metaWriter);
         }
-        for (Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
-            final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
+        for (Entry<AugmentationSchemaNode, Collection<AbstractNodeDataWithSchema<?>>> augmentationToChild
+                : augmentationsToChild.asMap().entrySet()) {
+            final Collection<AbstractNodeDataWithSchema<?>> childsFromAgumentation = augmentationToChild.getValue();
             if (!childsFromAgumentation.isEmpty()) {
                 // FIXME: can we get the augmentation schema?
-                writer.startAugmentationNode(getNodeIdentifierForAugmentation(augmentationToChild.getKey()));
+                writer.startAugmentationNode(DataSchemaContextNode.augmentationIdentifierFrom(
+                    augmentationToChild.getKey()));
 
-                for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
-                    nodeDataWithSchema.write(writer);
+                for (AbstractNodeDataWithSchema<?> nodeDataWithSchema : childsFromAgumentation) {
+                    nodeDataWithSchema.write(writer, metaWriter);
                 }
 
                 writer.endNode();
@@ -216,9 +224,10 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
      * @param child child node
      * @return augmentation schema
      */
-    private AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
+    private static AugmentationSchemaNode findCorrespondingAugment(final DataSchemaNode parent,
+            final DataSchemaNode child) {
         if (parent instanceof AugmentationTarget && !(parent instanceof ChoiceSchemaNode)) {
-            for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
+            for (AugmentationSchemaNode augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
                 DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
                 if (childInAugmentation != null) {
                     return augmentation;
@@ -227,16 +236,4 @@ public class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         }
         return null;
     }
-
-    public static YangInstanceIdentifier.AugmentationIdentifier getNodeIdentifierForAugmentation(final AugmentationSchema schema) {
-        final Collection<QName> qnames = Collections2.transform(schema.getChildNodes(), QNAME_FUNCTION);
-        return new YangInstanceIdentifier.AugmentationIdentifier(ImmutableSet.copyOf(qnames));
-    }
-
-    private static final Function<DataSchemaNode, QName> QNAME_FUNCTION = new Function<DataSchemaNode, QName>() {
-        @Override
-        public QName apply(@Nonnull final DataSchemaNode input) {
-            return input.getQName();
-        }
-    };
 }