Add DataTreeCandidateInputOutput 74/88474/3
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 18 Mar 2020 10:27:54 +0000 (11:27 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 18 Mar 2020 10:39:32 +0000 (11:39 +0100)
DataTreeCandidate is a yangtools concept, which is commonly
serialized by users of DataTree. Make sure we support its serialization
in the binary stream -- importing the implementation from controller
as of e66759266dc43d5f58b2837aca5047b42c205e4a.

Change-Id: I5d63a3f9b1ced38e762ce0a74fb3fd820d67614a
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractDataTreeCandidateNode.java [new file with mode: 0644]
yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DataTreeCandidateInputOutput.java [new file with mode: 0644]
yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DeletedDataTreeCandidateNode.java [new file with mode: 0644]
yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/ModifiedDataTreeCandidateNode.java [new file with mode: 0644]

diff --git a/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractDataTreeCandidateNode.java b/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractDataTreeCandidateNode.java
new file mode 100644 (file)
index 0000000..7d4a876
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.binfmt;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Collection;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+
+/**
+ * Abstract base class for our internal implementation of {@link DataTreeCandidateNode},
+ * which we instantiate from a serialized stream. We do not retain the before-image and
+ * do not implement {@link #getModifiedChild(PathArgument)}, as that method is only
+ * useful for end users. Instances based on this class should never be leaked outside of
+ * this component.
+ */
+abstract class AbstractDataTreeCandidateNode implements DataTreeCandidateNode {
+    private final ModificationType type;
+
+    protected AbstractDataTreeCandidateNode(final ModificationType type) {
+        this.type = requireNonNull(type);
+    }
+
+    @Override
+    public final Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    @Override
+    public final ModificationType getModificationType() {
+        return type;
+    }
+
+    @Override
+    public final Optional<NormalizedNode<?, ?>> getDataBefore() {
+        throw new UnsupportedOperationException("Before-image not available after serialization");
+    }
+
+    static DataTreeCandidateNode createUnmodified() {
+        return new AbstractDataTreeCandidateNode(ModificationType.UNMODIFIED) {
+            @Override
+            public PathArgument getIdentifier() {
+                throw new UnsupportedOperationException("Root node does not have an identifier");
+            }
+
+            @Override
+            public Optional<NormalizedNode<?, ?>> getDataAfter() {
+                throw new UnsupportedOperationException("After-image not available after serialization");
+            }
+
+            @Override
+            public Collection<DataTreeCandidateNode> getChildNodes() {
+                throw new UnsupportedOperationException("Children not available after serialization");
+            }
+        };
+    }
+}
diff --git a/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DataTreeCandidateInputOutput.java b/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DataTreeCandidateInputOutput.java
new file mode 100644 (file)
index 0000000..3d23fc5
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.binfmt;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.ReusableStreamReceiver;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.impl.schema.ReusableImmutableNormalizedNodeStreamWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility serialization/deserialization for {@link DataTreeCandidate}. Note that this utility does not maintain
+ * before-image information across serialization.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class DataTreeCandidateInputOutput {
+    private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidateInputOutput.class);
+    private static final byte DELETE = 0;
+    private static final byte SUBTREE_MODIFIED = 1;
+    private static final byte UNMODIFIED = 2;
+    private static final byte WRITE = 3;
+    private static final byte APPEARED = 4;
+    private static final byte DISAPPEARED = 5;
+
+    private DataTreeCandidateInputOutput() {
+
+    }
+
+    public static @NonNull DataTreeCandidate readDataTreeCandidate(final NormalizedNodeDataInput in)
+            throws IOException {
+        return readDataTreeCandidate(in, ReusableImmutableNormalizedNodeStreamWriter.create());
+    }
+
+    public static @NonNull DataTreeCandidate readDataTreeCandidate(final NormalizedNodeDataInput in,
+            final ReusableStreamReceiver receiver) throws IOException {
+        final YangInstanceIdentifier rootPath = in.readYangInstanceIdentifier();
+        final byte type = in.readByte();
+
+        final DataTreeCandidateNode rootNode;
+        switch (type) {
+            case APPEARED:
+                rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.APPEARED, readChildren(in, receiver));
+                break;
+            case DELETE:
+                rootNode = DeletedDataTreeCandidateNode.create();
+                break;
+            case DISAPPEARED:
+                rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.DISAPPEARED,
+                    readChildren(in, receiver));
+                break;
+            case SUBTREE_MODIFIED:
+                rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.SUBTREE_MODIFIED,
+                    readChildren(in, receiver));
+                break;
+            case WRITE:
+                rootNode = DataTreeCandidateNodes.written(in.readNormalizedNode(receiver));
+                break;
+            case UNMODIFIED:
+                rootNode = AbstractDataTreeCandidateNode.createUnmodified();
+                break;
+            default:
+                throw new IllegalArgumentException("Unhandled node type " + type);
+        }
+
+        return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
+    }
+
+    public static void writeDataTreeCandidate(final NormalizedNodeDataOutput out, final DataTreeCandidate candidate)
+            throws IOException {
+        out.writeYangInstanceIdentifier(candidate.getRootPath());
+
+        final DataTreeCandidateNode node = candidate.getRootNode();
+        switch (node.getModificationType()) {
+            case APPEARED:
+                out.writeByte(APPEARED);
+                writeChildren(out, node.getChildNodes());
+                break;
+            case DELETE:
+                out.writeByte(DELETE);
+                break;
+            case DISAPPEARED:
+                out.writeByte(DISAPPEARED);
+                writeChildren(out, node.getChildNodes());
+                break;
+            case SUBTREE_MODIFIED:
+                out.writeByte(SUBTREE_MODIFIED);
+                writeChildren(out, node.getChildNodes());
+                break;
+            case UNMODIFIED:
+                out.writeByte(UNMODIFIED);
+                break;
+            case WRITE:
+                out.writeByte(WRITE);
+                out.writeNormalizedNode(node.getDataAfter().get());
+                break;
+            default:
+                throwUnhandledNodeType(node);
+        }
+    }
+
+    private static DataTreeCandidateNode readModifiedNode(final ModificationType type, final NormalizedNodeDataInput in,
+            final ReusableStreamReceiver receiver) throws IOException {
+        final PathArgument identifier = in.readPathArgument();
+        final Collection<DataTreeCandidateNode> children = readChildren(in, receiver);
+        if (children.isEmpty()) {
+            LOG.debug("Modified node {} does not have any children, not instantiating it", identifier);
+            return null;
+        }
+
+        return ModifiedDataTreeCandidateNode.create(identifier, type, children);
+    }
+
+    private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in,
+            final ReusableStreamReceiver receiver) throws IOException {
+        final int size = in.readInt();
+        if (size == 0) {
+            return ImmutableList.of();
+        }
+
+        final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
+        for (int i = 0; i < size; ++i) {
+            final DataTreeCandidateNode child = readNode(in, receiver);
+            if (child != null) {
+                ret.add(child);
+            }
+        }
+        return ret;
+    }
+
+    private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in,
+            final ReusableStreamReceiver receiver) throws IOException {
+        final byte type = in.readByte();
+        switch (type) {
+            case APPEARED:
+                return readModifiedNode(ModificationType.APPEARED, in, receiver);
+            case DELETE:
+                return DeletedDataTreeCandidateNode.create(in.readPathArgument());
+            case DISAPPEARED:
+                return readModifiedNode(ModificationType.DISAPPEARED, in, receiver);
+            case SUBTREE_MODIFIED:
+                return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in, receiver);
+            case UNMODIFIED:
+                return null;
+            case WRITE:
+                return DataTreeCandidateNodes.written(in.readNormalizedNode(receiver));
+            default:
+                throw new IllegalArgumentException("Unhandled node type " + type);
+        }
+    }
+
+    private static void writeChildren(final NormalizedNodeDataOutput out,
+            final Collection<DataTreeCandidateNode> children) throws IOException {
+        out.writeInt(children.size());
+        for (DataTreeCandidateNode child : children) {
+            writeNode(out, child);
+        }
+    }
+
+    private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
+            throws IOException {
+        switch (node.getModificationType()) {
+            case APPEARED:
+                out.writeByte(APPEARED);
+                out.writePathArgument(node.getIdentifier());
+                writeChildren(out, node.getChildNodes());
+                break;
+            case DELETE:
+                out.writeByte(DELETE);
+                out.writePathArgument(node.getIdentifier());
+                break;
+            case DISAPPEARED:
+                out.writeByte(DISAPPEARED);
+                out.writePathArgument(node.getIdentifier());
+                writeChildren(out, node.getChildNodes());
+                break;
+            case SUBTREE_MODIFIED:
+                out.writeByte(SUBTREE_MODIFIED);
+                out.writePathArgument(node.getIdentifier());
+                writeChildren(out, node.getChildNodes());
+                break;
+            case WRITE:
+                out.writeByte(WRITE);
+                out.writeNormalizedNode(node.getDataAfter().get());
+                break;
+            case UNMODIFIED:
+                out.writeByte(UNMODIFIED);
+                break;
+            default:
+                throwUnhandledNodeType(node);
+        }
+    }
+
+    private static void throwUnhandledNodeType(final DataTreeCandidateNode node) {
+        throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
+    }
+}
diff --git a/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DeletedDataTreeCandidateNode.java b/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/DeletedDataTreeCandidateNode.java
new file mode 100644 (file)
index 0000000..c3e6b9b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.binfmt;
+
+import java.util.Collection;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+
+/**
+ * A deserialized {@link DataTreeCandidateNode} which represents a deletion.
+ */
+abstract class DeletedDataTreeCandidateNode extends AbstractDataTreeCandidateNode {
+    private DeletedDataTreeCandidateNode() {
+        super(ModificationType.DELETE);
+    }
+
+    static DataTreeCandidateNode create() {
+        return new DeletedDataTreeCandidateNode() {
+            @Override
+            public PathArgument getIdentifier() {
+                throw new UnsupportedOperationException("Root node does not have an identifier");
+            }
+        };
+    }
+
+    static DataTreeCandidateNode create(final PathArgument identifier) {
+        return new DeletedDataTreeCandidateNode() {
+            @Override
+            public PathArgument getIdentifier() {
+                return identifier;
+            }
+        };
+    }
+
+    @Override
+    public final Optional<NormalizedNode<?, ?>> getDataAfter() {
+        return Optional.empty();
+    }
+
+    @Override
+    public final Collection<DataTreeCandidateNode> getChildNodes() {
+        // We would require the before-image to reconstruct the list of nodes which
+        // were deleted.
+        throw new UnsupportedOperationException("Children not available after serialization");
+    }
+}
diff --git a/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/ModifiedDataTreeCandidateNode.java b/yang/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/ModifiedDataTreeCandidateNode.java
new file mode 100644 (file)
index 0000000..4b156f2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.binfmt;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Collection;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+
+/**
+ * A deserialized {@link DataTreeCandidateNode} which represents a modification in
+ * one of its children.
+ */
+abstract class ModifiedDataTreeCandidateNode extends AbstractDataTreeCandidateNode {
+    private final Collection<DataTreeCandidateNode> children;
+
+    private ModifiedDataTreeCandidateNode(final ModificationType type,
+            final Collection<DataTreeCandidateNode> children) {
+        super(type);
+        this.children = requireNonNull(children);
+    }
+
+    static DataTreeCandidateNode create(final ModificationType type, final Collection<DataTreeCandidateNode> children) {
+        return new ModifiedDataTreeCandidateNode(type, children) {
+            @Override
+            public PathArgument getIdentifier() {
+                throw new UnsupportedOperationException("Root node does not have an identifier");
+            }
+        };
+    }
+
+    static DataTreeCandidateNode create(final PathArgument identifier, final ModificationType type,
+            final Collection<DataTreeCandidateNode> children) {
+        return new ModifiedDataTreeCandidateNode(type, children) {
+            @Override
+            public PathArgument getIdentifier() {
+                return identifier;
+            }
+        };
+    }
+
+    @Override
+    public final Optional<NormalizedNode<?, ?>> getDataAfter() {
+        throw new UnsupportedOperationException("After-image not available after serialization");
+    }
+
+    @Override
+    public final Collection<DataTreeCandidateNode> getChildNodes() {
+        return children;
+    }
+}