Add MultipleEntryDataWithSchema interface
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / ListEntryNodeDataWithSchema.java
index 13a734d28d1b4fdae48cfaf1a9a999aae69db296..5f75ccdea95397bbee642274faa8ac21c965e29d 100644 (file)
@@ -7,12 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.data.util;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Verify.verify;
+
 import java.io.IOException;
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension;
+import org.opendaylight.yangtools.util.ImmutableMapTemplate;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
@@ -27,57 +30,65 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
  * <p>
  * Represents a YANG list entry node.
  */
-public class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
+public abstract class ListEntryNodeDataWithSchema extends AbstractMountPointDataWithSchema<ListSchemaNode> {
+    private static final class Keyed extends ListEntryNodeDataWithSchema {
+        private final Map<QName, SimpleNodeDataWithSchema<?>> keyValues = new HashMap<>();
+        // This template results in Maps in schema definition order
+        private final ImmutableMapTemplate<QName> predicateTemplate;
 
-    private final Map<QName, SimpleNodeDataWithSchema> qnameToKeys = new HashMap<>();
+        Keyed(final ListSchemaNode schema, final List<QName> keyDef) {
+            super(schema);
+            predicateTemplate = ImmutableMapTemplate.ordered(keyDef);
+        }
 
-    public ListEntryNodeDataWithSchema(final DataSchemaNode schema) {
-        super(schema);
-    }
+        @Override
+        public void addChild(final AbstractNodeDataWithSchema<?> newChild) {
+            final DataSchemaNode childSchema = newChild.getSchema();
+            if (childSchema instanceof LeafSchemaNode) {
+                final QName childName = childSchema.getQName();
+                if (predicateTemplate.keySet().contains(childName)) {
+                    verify(newChild instanceof SimpleNodeDataWithSchema);
+                    keyValues.put(childName, (SimpleNodeDataWithSchema<?>)newChild);
+                }
+            }
+            super.addChild(newChild);
+        }
+
+        @Override
+        public void write(final NormalizedNodeStreamWriter writer, final StreamWriterMetadataExtension metaWriter)
+                throws IOException {
+            writer.nextDataSchemaNode(getSchema());
+            final NodeIdentifierWithPredicates identifier = NodeIdentifierWithPredicates.of(getSchema().getQName(),
+                predicateTemplate.instantiateTransformed(keyValues, (key, node) -> node.getValue()));
 
-    @Override
-    public void addChild(final AbstractNodeDataWithSchema newChild) {
-        final DataSchemaNode childSchema = newChild.getSchema();
-        if (childSchema instanceof LeafSchemaNode && isPartOfKey((LeafSchemaNode) childSchema)) {
-            qnameToKeys.put(childSchema.getQName(), (SimpleNodeDataWithSchema)newChild);
+            writer.startMapEntryNode(identifier, childSizeHint());
+            writeMetadata(metaWriter);
+            super.write(writer, metaWriter);
+            writer.endNode();
         }
-        super.addChild(newChild);
     }
 
-    private boolean isPartOfKey(final LeafSchemaNode potentialKey) {
-        for (QName qname : ((ListSchemaNode) getSchema()).getKeyDefinition()) {
-            if (qname.equals(potentialKey.getQName())) {
-                return true;
-            }
+    private static final class Unkeyed extends ListEntryNodeDataWithSchema {
+        Unkeyed(final ListSchemaNode schema) {
+            super(schema);
         }
-        return false;
-    }
 
-    @Override
-    public void write(final NormalizedNodeStreamWriter writer) throws IOException {
-        final Collection<QName> keyDef = ((ListSchemaNode) getSchema()).getKeyDefinition();
-        if (keyDef.isEmpty()) {
+        @Override
+        public void write(final NormalizedNodeStreamWriter writer, final StreamWriterMetadataExtension metaWriter)
+                throws IOException {
             writer.nextDataSchemaNode(getSchema());
             writer.startUnkeyedListItem(provideNodeIdentifier(), childSizeHint());
-            super.write(writer);
+            super.write(writer, metaWriter);
             writer.endNode();
-            return;
         }
+    }
 
-        Preconditions.checkState(keyDef.size() == qnameToKeys.size(), "Input is missing some of the keys of %s",
-                getSchema().getQName());
-
-        // Need to restore schema order...
-        final Map<QName, Object> predicates = new LinkedHashMap<>();
-        for (QName qname : keyDef) {
-            predicates.put(qname, qnameToKeys.get(qname).getValue());
-        }
+    ListEntryNodeDataWithSchema(final ListSchemaNode schema) {
+        super(schema);
+    }
 
-        writer.nextDataSchemaNode(getSchema());
-        writer.startMapEntryNode(
-            new NodeIdentifierWithPredicates(getSchema().getQName(), predicates),
-            childSizeHint());
-        super.write(writer);
-        writer.endNode();
+    public static @NonNull ListEntryNodeDataWithSchema forSchema(final ListSchemaNode schema) {
+        final List<QName> keyDef = schema.getKeyDefinition();
+        return keyDef.isEmpty() ? new Unkeyed(schema) :  new Keyed(schema, keyDef);
     }
 }