Refactor PathArgument to DataObjectStep
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / BindingToNormalizedStreamWriter.java
index fc982428b8427d02e061d3aab26250daeb2cfaf9..2bf031865aa797280b751faf408213c6175b1f9f 100644 (file)
@@ -7,86 +7,84 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
-import com.google.common.base.Preconditions;
+import static java.util.Objects.requireNonNull;
+
 import java.io.IOException;
 import java.util.AbstractMap;
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.Map;
 import java.util.Map.Entry;
+import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.Identifiable;
-import org.opendaylight.yangtools.yang.binding.Identifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.binding.Key;
+import org.opendaylight.yangtools.yang.binding.KeyAware;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 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.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
-final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Delegator<NormalizedNodeStreamWriter> {
-    private final Deque<NodeCodecContext<?>> schema = new ArrayDeque<>();
-    private final NormalizedNodeStreamWriter delegate;
-    private final NodeCodecContext<?> rootNodeSchema;
-
-    BindingToNormalizedStreamWriter(final NodeCodecContext<?> rootNodeSchema,
-            final NormalizedNodeStreamWriter delegate) {
-        this.rootNodeSchema = Preconditions.checkNotNull(rootNodeSchema);
-        this.delegate = Preconditions.checkNotNull(delegate);
-    }
+final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWriter,
+        Delegator<NormalizedNodeStreamWriter> {
+    private final Deque<CodecContext> schema = new ArrayDeque<>();
+    private final @NonNull NormalizedNodeStreamWriter delegate;
+    private final CodecContext rootContext;
 
-    static BindingToNormalizedStreamWriter create(final NodeCodecContext<?> schema,
+    BindingToNormalizedStreamWriter(final DataContainerCodecContext<?, ?, ?> rootContext,
             final NormalizedNodeStreamWriter delegate) {
-        return new BindingToNormalizedStreamWriter(schema, delegate);
+        this.rootContext = requireNonNull(rootContext);
+        this.delegate = requireNonNull(delegate);
     }
 
     private void emitSchema(final Object schemaNode) {
         delegate.nextDataSchemaNode((DataSchemaNode) schemaNode);
     }
 
-    NodeCodecContext<?> current() {
+    CodecContext current() {
         return schema.peek();
     }
 
     private NodeIdentifier duplicateSchemaEnter() {
-        final NodeCodecContext<?> next;
-        if (current() == null) {
+        final var current = current();
+        final CodecContext next;
+        if (current == null) {
             // Entry of first node
-            next = rootNodeSchema;
+            next = rootContext;
         } else {
-            next = current();
+            next = current;
         }
-        this.schema.push(next);
-        return (NodeIdentifier) current().getDomPathArgument();
+        schema.push(next);
+        return next.getDomPathArgument();
     }
 
     @SuppressWarnings({"unchecked", "rawtypes"})
-    private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
-        final NodeCodecContext<?> next;
-        if (current() == null) {
+    private <T extends PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
+        final var current = current();
+        final CodecContext next;
+        if (current == null) {
             // Entry of first node
-            next = rootNodeSchema;
+            next = rootContext;
+        } else if (current instanceof DataContainerCodecContext<?, ?, ?> currentContainer) {
+            next = currentContainer.getStreamChild((Class) name);
         } else {
-            Preconditions.checkArgument(current() instanceof DataContainerCodecContext, "Could not start node %s",
-                    name);
-            next = ((DataContainerCodecContext<?,?>) current()).streamChild((Class) name);
+            throw new IllegalArgumentException("Could not start node " + name + " in non-container " + current);
         }
-        this.schema.push(next);
-        T arg = (T) next.getDomPathArgument();
-        return arg;
+        schema.push(next);
+        return identifier.cast(next.getDomPathArgument());
     }
 
-    private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
-        NodeCodecContext<?> current = current();
-        NodeCodecContext<?> next = ((DataObjectCodecContext<?,?>) current).getLeafChild(localName);
-        this.schema.push(next);
-        @SuppressWarnings("unchecked")
-        T arg = (T) next.getDomPathArgument();
-        return arg;
+    private <T extends PathArgument> T enter(final String localName, final Class<T> identifier) {
+        final var current = current();
+        final var next = ((AbstractDataObjectCodecContext<?, ?>) current).getLeafChild(localName);
+        schema.push(next);
+        return identifier.cast(next.getDomPathArgument());
     }
 
     @Override
@@ -96,21 +94,22 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter,
 
     @Override
     public void endNode() throws IOException {
-        NodeCodecContext<?> left = schema.pop();
-        // NormalizedNode writer does not have entry into case, but into choice
-        // so for leaving case, we do not emit endNode.
-        if (!(left instanceof CaseNodeCodecContext)) {
-            getDelegate().endNode();
+        CodecContext left = schema.pop();
+        // Due to writer does not start a new node on startCase() and on startAugmentationNode()
+        // node ending should not be triggered when associated endNode() is invoked.
+        if (!(left instanceof CaseCodecContext) && !(left instanceof AugmentationCodecContext)) {
+            delegate.endNode();
         }
     }
 
     private Map.Entry<NodeIdentifier, Object> serializeLeaf(final String localName, final Object value) {
-        Preconditions.checkArgument(current() instanceof DataObjectCodecContext);
-
-        DataObjectCodecContext<?,?> currentCasted = (DataObjectCodecContext<?,?>) current();
-        LeafNodeCodecContext<?> leafContext = currentCasted.getLeafChild(localName);
+        final var current = current();
+        if (!(current instanceof AbstractDataObjectCodecContext<?, ?> currentCasted)) {
+            throw new IllegalArgumentException("Unexpected current context " + current);
+        }
 
-        NodeIdentifier domArg = (NodeIdentifier) leafContext.getDomPathArgument();
+        ValueNodeCodecContext leafContext = currentCasted.getLeafChild(localName);
+        NodeIdentifier domArg = leafContext.getDomPathArgument();
         Object domValue = leafContext.getValueCodec().serialize(value);
         emitSchema(leafContext.getSchema());
         return new AbstractMap.SimpleEntry<>(domArg, domValue);
@@ -118,27 +117,43 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter,
 
     @Override
     public void leafNode(final String localName, final Object value) throws IOException {
-        Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
-        getDelegate().leafNode(dom.getKey(), dom.getValue());
+        final Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
+        delegate.startLeafNode(dom.getKey());
+        delegate.scalarValue(dom.getValue());
+        delegate.endNode();
+    }
+
+    @Override
+    public void anydataNode(final String name, final OpaqueObject<?> value) throws IOException {
+        final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+        if (delegate.startAnydataNode(dom.getKey(), value.getValue().getObjectModel())) {
+            delegate.scalarValue(dom.getValue());
+            delegate.endNode();
+        }
     }
 
     @Override
     public void anyxmlNode(final String name, final Object value) throws IOException {
-        Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
-        getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
+        final Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
+        // FIXME: this is not quite right -- we should be handling other object models, too
+        if (delegate.startAnyxmlNode(dom.getKey(), DOMSource.class)) {
+            delegate.domSourceValue((DOMSource) dom.getValue());
+            delegate.endNode();
+        }
     }
 
     @Override
     public void leafSetEntryNode(final Object value) throws IOException {
-        LeafNodeCodecContext<?> ctx = (LeafNodeCodecContext<?>) current();
-        getDelegate().leafSetEntryNode(ctx.getSchema().getQName(),
-            ctx.getValueCodec().serialize(value));
+        final LeafSetNodeCodecContext ctx = (LeafSetNodeCodecContext) current();
+        final Object domValue = ctx.getValueCodec().serialize(value);
+        delegate.startLeafSetEntryNode(new NodeWithValue<>(ctx.getSchema().getQName(), domValue));
+        delegate.scalarValue(domValue);
+        delegate.endNode();
     }
 
     @Override
-    public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
-            throws IOException {
-        getDelegate().startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
+    public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType) throws IOException {
+        enter(augmentationType, NodeIdentifier.class);
     }
 
     @Override
@@ -149,63 +164,63 @@ final class BindingToNormalizedStreamWriter implements BindingStreamEventWriter,
     @Override
     public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
             throws IOException {
-        getDelegate().startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
+        delegate.startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
     public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
             throws IOException {
-        getDelegate().startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
+        delegate.startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
     public void startLeafSet(final String localName, final int childSizeHint) throws IOException {
         final NodeIdentifier id = enter(localName, NodeIdentifier.class);
         emitSchema(current().getSchema());
-        getDelegate().startLeafSet(id, childSizeHint);
+        delegate.startLeafSet(id, childSizeHint);
     }
 
     @Override
     public void startOrderedLeafSet(final String localName, final int childSizeHint) throws IOException {
-        getDelegate().startOrderedLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
+        delegate.startOrderedLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
-    public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IOException {
+    public void startMapEntryNode(final Key<?> key, final int childSizeHint) throws IOException {
         duplicateSchemaEnter();
-        NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?>) current()).serialize(key);
-        getDelegate().startMapEntryNode(identifier, childSizeHint);
+        NodeIdentifierWithPredicates identifier = ((MapCodecContext<?, ?>) current()).serialize(key);
+        delegate.startMapEntryNode(identifier, childSizeHint);
     }
 
     @Override
-    public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
-            final int childSizeHint) throws IOException {
-        getDelegate().startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+    public <T extends DataObject & KeyAware<?>> void startMapNode(final Class<T> mapEntryType, final int childSizeHint)
+            throws IOException {
+        delegate.startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
-    public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
+    public <T extends DataObject & KeyAware<?>> void startOrderedMapNode(final Class<T> mapEntryType,
             final int childSizeHint) throws IOException {
-        getDelegate().startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
+        delegate.startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
     public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint) throws IOException {
-        getDelegate().startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
+        delegate.startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
     public void startUnkeyedListItem(final int childSizeHint) throws IOException {
-        getDelegate().startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
+        delegate.startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
     }
 
     @Override
     public void flush() throws IOException {
-        getDelegate().flush();
+        delegate.flush();
     }
 
     @Override
     public void close() throws IOException {
-        getDelegate().close();
+        delegate.close();
     }
 }