BUG-4626: create AbstractNormalizedNodeDataOutput 08/31008/5
authorRobert Varga <rovarga@cisco.com>
Tue, 8 Dec 2015 13:02:50 +0000 (14:02 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 10 Dec 2015 13:08:15 +0000 (13:08 +0000)
Create an internal NormalizedNodeDataOutput implementation for reuse of
code between stream versions.

Change-Id: I60e68fe150ba49d37a6821b057b9ef93a8e600e5
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java

diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.java
new file mode 100644 (file)
index 0000000..f8ea298
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * 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.controller.cluster.datastore.node.utils.stream;
+
+import com.google.common.base.Preconditions;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.api.schema.stream.NormalizedNodeWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOutput, NormalizedNodeStreamWriter {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodeDataOutput.class);
+
+    private final DataOutput output;
+
+    private NormalizedNodeWriter normalizedNodeWriter;
+    private boolean headerWritten;
+
+    AbstractNormalizedNodeDataOutput(final DataOutput output) {
+        this.output = Preconditions.checkNotNull(output);
+    }
+
+    private void ensureHeaderWritten() throws IOException {
+        if (!headerWritten) {
+            output.writeByte(TokenTypes.SIGNATURE_MARKER);
+            output.writeShort(streamVersion());
+            headerWritten = true;
+        }
+    }
+
+    protected abstract short streamVersion();
+    protected abstract void writeQName(QName qname) throws IOException;
+    protected abstract void writeString(String string) throws IOException;
+
+    @Override
+    public final void write(final int b) throws IOException {
+        ensureHeaderWritten();
+        output.write(b);
+    }
+
+    @Override
+    public final void write(final byte[] b) throws IOException {
+        ensureHeaderWritten();
+        output.write(b);
+    }
+
+    @Override
+    public final void write(final byte[] b, final int off, final int len) throws IOException {
+        ensureHeaderWritten();
+        output.write(b, off, len);
+    }
+
+    @Override
+    public final void writeBoolean(final boolean v) throws IOException {
+        ensureHeaderWritten();
+        output.writeBoolean(v);
+    }
+
+    @Override
+    public final void writeByte(final int v) throws IOException {
+        ensureHeaderWritten();
+        output.writeByte(v);
+    }
+
+    @Override
+    public final void writeShort(final int v) throws IOException {
+        ensureHeaderWritten();
+        output.writeShort(v);
+    }
+
+    @Override
+    public final void writeChar(final int v) throws IOException {
+        ensureHeaderWritten();
+        output.writeChar(v);
+    }
+
+    @Override
+    public final void writeInt(final int v) throws IOException {
+        ensureHeaderWritten();
+        output.writeInt(v);
+    }
+
+    @Override
+    public final void writeLong(final long v) throws IOException {
+        ensureHeaderWritten();
+        output.writeLong(v);
+    }
+
+    @Override
+    public final void writeFloat(final float v) throws IOException {
+        ensureHeaderWritten();
+        output.writeFloat(v);
+    }
+
+    @Override
+    public final void writeDouble(final double v) throws IOException {
+        ensureHeaderWritten();
+        output.writeDouble(v);
+    }
+
+    @Override
+    public final void writeBytes(final String s) throws IOException {
+        ensureHeaderWritten();
+        output.writeBytes(s);
+    }
+
+    @Override
+    public final void writeChars(final String s) throws IOException {
+        ensureHeaderWritten();
+        output.writeChars(s);
+    }
+
+    @Override
+    public final void writeUTF(final String s) throws IOException {
+        ensureHeaderWritten();
+        output.writeUTF(s);
+    }
+
+    private NormalizedNodeWriter normalizedNodeWriter() {
+        if(normalizedNodeWriter == null) {
+            normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(this);
+        }
+
+        return normalizedNodeWriter;
+    }
+
+    @Override
+    public void writeNormalizedNode(final NormalizedNode<?, ?> node) throws IOException {
+        ensureHeaderWritten();
+        normalizedNodeWriter().write(node);
+    }
+
+    @Override
+    public void leafNode(final YangInstanceIdentifier.NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Writing a new leaf node");
+        startNode(name.getNodeType(), NodeTypes.LEAF_NODE);
+
+        writeObject(value);
+    }
+
+    @Override
+    public void startLeafSet(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new leaf set");
+
+        startNode(name.getNodeType(), NodeTypes.LEAF_SET);
+    }
+
+    @Override
+    public void leafSetEntryNode(final Object value) throws IOException, IllegalArgumentException {
+        LOG.debug("Writing a new leaf set entry node");
+
+        output.writeByte(NodeTypes.LEAF_SET_ENTRY_NODE);
+        writeObject(value);
+    }
+
+    @Override
+    public void startContainerNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+
+        LOG.debug("Starting a new container node");
+
+        startNode(name.getNodeType(), NodeTypes.CONTAINER_NODE);
+    }
+
+    @Override
+    public void startYangModeledAnyXmlNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+
+        LOG.debug("Starting a new yang modeled anyXml node");
+
+        startNode(name.getNodeType(), NodeTypes.YANG_MODELED_ANY_XML_NODE);
+    }
+
+    @Override
+    public void startUnkeyedList(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new unkeyed list");
+
+        startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST);
+    }
+
+    @Override
+    public void startUnkeyedListItem(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalStateException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new unkeyed list item");
+
+        startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST_ITEM);
+    }
+
+    @Override
+    public void startMapNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new map node");
+
+        startNode(name.getNodeType(), NodeTypes.MAP_NODE);
+    }
+
+    @Override
+    public void startMapEntryNode(final YangInstanceIdentifier.NodeIdentifierWithPredicates identifier, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(identifier, "Node identifier should not be null");
+        LOG.debug("Starting a new map entry node");
+        startNode(identifier.getNodeType(), NodeTypes.MAP_ENTRY_NODE);
+
+        writeKeyValueMap(identifier.getKeyValues());
+
+    }
+
+    @Override
+    public void startOrderedMapNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new ordered map node");
+
+        startNode(name.getNodeType(), NodeTypes.ORDERED_MAP_NODE);
+    }
+
+    @Override
+    public void startChoiceNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Starting a new choice node");
+
+        startNode(name.getNodeType(), NodeTypes.CHOICE_NODE);
+    }
+
+    @Override
+    public void startAugmentationNode(final YangInstanceIdentifier.AugmentationIdentifier identifier) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(identifier, "Node identifier should not be null");
+        LOG.debug("Starting a new augmentation node");
+
+        output.writeByte(NodeTypes.AUGMENTATION_NODE);
+        writeQNameSet(identifier.getPossibleChildNames());
+    }
+
+    @Override
+    public void anyxmlNode(final YangInstanceIdentifier.NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
+        Preconditions.checkNotNull(name, "Node identifier should not be null");
+        LOG.debug("Writing a new xml node");
+
+        startNode(name.getNodeType(), NodeTypes.ANY_XML_NODE);
+
+        writeObject(value);
+    }
+
+    @Override
+    public void endNode() throws IOException, IllegalStateException {
+        LOG.debug("Ending the node");
+
+        output.writeByte(NodeTypes.END_NODE);
+    }
+
+    @Override
+    public void close() throws IOException {
+        flush();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        if (output instanceof OutputStream) {
+            ((OutputStream)output).flush();
+        }
+    }
+
+    private void startNode(final QName qName, final byte nodeType) throws IOException {
+
+        Preconditions.checkNotNull(qName, "QName of node identifier should not be null.");
+
+        ensureHeaderWritten();
+
+        // First write the type of node
+        output.writeByte(nodeType);
+        // Write Start Tag
+        writeQName(qName);
+    }
+
+    private void writeObjSet(final Set<?> set) throws IOException {
+        output.writeInt(set.size());
+        for (Object o : set) {
+            Preconditions.checkArgument(o instanceof String, "Expected value type to be String but was %s (%s)",
+                o.getClass(), o);
+
+            writeString((String) o);
+        }
+    }
+
+    @Override
+    public void writeYangInstanceIdentifier(final YangInstanceIdentifier identifier) throws IOException {
+        ensureHeaderWritten();
+        writeYangInstanceIdentifierInternal(identifier);
+    }
+
+    private void writeYangInstanceIdentifierInternal(final YangInstanceIdentifier identifier) throws IOException {
+        Collection<YangInstanceIdentifier.PathArgument> pathArguments = identifier.getPathArguments();
+        output.writeInt(pathArguments.size());
+
+        for(YangInstanceIdentifier.PathArgument pathArgument : pathArguments) {
+            writePathArgument(pathArgument);
+        }
+    }
+
+    @Override
+    public void writePathArgument(final YangInstanceIdentifier.PathArgument pathArgument) throws IOException {
+
+        byte type = PathArgumentTypes.getSerializablePathArgumentType(pathArgument);
+
+        output.writeByte(type);
+
+        switch(type) {
+            case PathArgumentTypes.NODE_IDENTIFIER:
+
+                YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
+                    (YangInstanceIdentifier.NodeIdentifier) pathArgument;
+
+                writeQName(nodeIdentifier.getNodeType());
+                break;
+
+            case PathArgumentTypes.NODE_IDENTIFIER_WITH_PREDICATES:
+
+                YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
+                    (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
+                writeQName(nodeIdentifierWithPredicates.getNodeType());
+
+                writeKeyValueMap(nodeIdentifierWithPredicates.getKeyValues());
+                break;
+
+            case PathArgumentTypes.NODE_IDENTIFIER_WITH_VALUE :
+
+                YangInstanceIdentifier.NodeWithValue nodeWithValue =
+                    (YangInstanceIdentifier.NodeWithValue) pathArgument;
+
+                writeQName(nodeWithValue.getNodeType());
+                writeObject(nodeWithValue.getValue());
+                break;
+
+            case PathArgumentTypes.AUGMENTATION_IDENTIFIER :
+
+                YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier =
+                    (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
+
+                // No Qname in augmentation identifier
+                writeQNameSet(augmentationIdentifier.getPossibleChildNames());
+                break;
+            default :
+                throw new IllegalStateException("Unknown node identifier type is found : " + pathArgument.getClass().toString() );
+        }
+    }
+
+    private void writeKeyValueMap(final Map<QName, Object> keyValueMap) throws IOException {
+        if (keyValueMap != null && !keyValueMap.isEmpty()) {
+            output.writeInt(keyValueMap.size());
+
+            for (QName qName : keyValueMap.keySet()) {
+                writeQName(qName);
+                writeObject(keyValueMap.get(qName));
+            }
+        } else {
+            output.writeInt(0);
+        }
+    }
+
+    private void writeQNameSet(final Set<QName> children) throws IOException {
+        // Write each child's qname separately, if list is empty send count as 0
+        if (children != null && !children.isEmpty()) {
+            output.writeInt(children.size());
+            for (QName qName : children) {
+                writeQName(qName);
+            }
+        } else {
+            LOG.debug("augmentation node does not have any child");
+            output.writeInt(0);
+        }
+    }
+
+    private void writeObject(final Object value) throws IOException {
+
+        byte type = ValueTypes.getSerializableType(value);
+        // Write object type first
+        output.writeByte(type);
+
+        switch (type) {
+            case ValueTypes.BOOL_TYPE:
+                output.writeBoolean((Boolean) value);
+                break;
+            case ValueTypes.QNAME_TYPE:
+                writeQName((QName) value);
+                break;
+            case ValueTypes.INT_TYPE:
+                output.writeInt((Integer) value);
+                break;
+            case ValueTypes.BYTE_TYPE:
+                output.writeByte((Byte) value);
+                break;
+            case ValueTypes.LONG_TYPE:
+                output.writeLong((Long) value);
+                break;
+            case ValueTypes.SHORT_TYPE:
+                output.writeShort((Short) value);
+                break;
+            case ValueTypes.BITS_TYPE:
+                writeObjSet((Set<?>) value);
+                break;
+            case ValueTypes.BINARY_TYPE:
+                byte[] bytes = (byte[]) value;
+                output.writeInt(bytes.length);
+                output.write(bytes);
+                break;
+            case ValueTypes.YANG_IDENTIFIER_TYPE:
+                writeYangInstanceIdentifierInternal((YangInstanceIdentifier) value);
+                break;
+            case ValueTypes.NULL_TYPE :
+                break;
+            case ValueTypes.STRING_BYTES_TYPE:
+                final byte[] valueBytes = value.toString().getBytes(StandardCharsets.UTF_8);
+                output.writeInt(valueBytes.length);
+                output.write(valueBytes);
+                break;
+            default:
+                output.writeUTF(value.toString());
+                break;
+        }
+    }
+}
index cb84ef881095725fa8a7ec0d9e3f7f79380c21a4..5b93b274e0b757766e750efa8c5f8a129e9f6eed 100644 (file)
@@ -7,18 +7,31 @@
  */
 package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
+import com.google.common.annotations.Beta;
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import javax.annotation.Nonnull;
 
+@Beta
 public final class NormalizedNodeInputOutput {
     private NormalizedNodeInputOutput() {
         throw new UnsupportedOperationException();
     }
 
     public static NormalizedNodeDataInput newDataInput(@Nonnull final DataInput input) throws IOException {
-        return new NormalizedNodeInputStreamReader(input);
+        final byte marker = input.readByte();
+        if (marker != TokenTypes.SIGNATURE_MARKER) {
+            throw new InvalidNormalizedNodeStreamException(String.format("Invalid signature marker: %d", marker));
+        }
+
+        final short version = input.readShort();
+        switch (version) {
+            case TokenTypes.LITHIUM_VERSION:
+                return new NormalizedNodeInputStreamReader(input, true);
+            default:
+                throw new InvalidNormalizedNodeStreamException(String.format("Unhandled stream version %s", version));
+        }
     }
 
     public static NormalizedNodeDataOutput newDataOutput(@Nonnull final DataOutput output) throws IOException {
index 9f6d39aa194c370eeeefced90a999e87f4523814..e1cb4b4c537b3e56dff9c416c7833b03d250b336 100644 (file)
@@ -75,8 +75,7 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput,
      */
     @Deprecated
     public NormalizedNodeInputStreamReader(final InputStream stream) throws IOException {
-        Preconditions.checkNotNull(stream);
-        input = new DataInputStream(stream);
+        this((DataInput) new DataInputStream(Preconditions.checkNotNull(stream)));
     }
 
     /**
@@ -84,7 +83,12 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput,
      */
     @Deprecated
     public NormalizedNodeInputStreamReader(final DataInput input) {
+        this(input, false);
+    }
+
+    NormalizedNodeInputStreamReader(final DataInput input, final boolean versionChecked) {
         this.input = Preconditions.checkNotNull(input);
+        readSignatureMarker = !versionChecked;
     }
 
     @Override
@@ -413,19 +417,19 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput,
     }
 
     @Override
-    public void readFully(byte[] b) throws IOException {
+    public void readFully(final byte[] b) throws IOException {
         readSignatureMarkerAndVersionIfNeeded();
         input.readFully(b);
     }
 
     @Override
-    public void readFully(byte[] b, int off, int len) throws IOException {
+    public void readFully(final byte[] b, final int off, final int len) throws IOException {
         readSignatureMarkerAndVersionIfNeeded();
         input.readFully(b, off, len);
     }
 
     @Override
-    public int skipBytes(int n) throws IOException {
+    public int skipBytes(final int n) throws IOException {
         readSignatureMarkerAndVersionIfNeeded();
         return input.skipBytes(n);
     }
index 473677396310513d73472bbc8ac8f410793e90a2..60250ffefd199e93f205ebe39ee96d9623ab6860 100644 (file)
@@ -13,46 +13,28 @@ import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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.api.schema.stream.NormalizedNodeWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * NormalizedNodeOutputStreamWriter will be used by distributed datastore to send normalized node in
  * a stream.
  * A stream writer wrapper around this class will write node objects to stream in recursive manner.
  * for example - If you have a ContainerNode which has a two LeafNode as children, then
- * you will first call {@link #startContainerNode(YangInstanceIdentifier.NodeIdentifier, int)}, then will call
- * {@link #leafNode(YangInstanceIdentifier.NodeIdentifier, Object)} twice and then, {@link #endNode()} to end
- * container node.
+ * you will first call
+ * {@link #startContainerNode(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier, int)},
+ * then will call
+ * {@link #leafNode(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier, Object)} twice
+ * and then, {@link #endNode()} to end container node.
  *
  * Based on the each node, the node type is also written to the stream, that helps in reconstructing the object,
  * while reading.
- *
- *
  */
-
-public class NormalizedNodeOutputStreamWriter implements NormalizedNodeDataOutput, NormalizedNodeStreamWriter {
-
-    private static final Logger LOG = LoggerFactory.getLogger(NormalizedNodeOutputStreamWriter.class);
-
-    private final DataOutput output;
-
+public class NormalizedNodeOutputStreamWriter extends AbstractNormalizedNodeDataOutput implements NormalizedNodeStreamWriter {
     private final Map<String, Integer> stringCodeMap = new HashMap<>();
 
-    private NormalizedNodeWriter normalizedNodeWriter;
-
-    private boolean wroteSignatureMarker;
-
     /**
      * @deprecated Use {@link #NormalizedNodeOutputStreamWriter(DataOutput)} instead.
      */
@@ -66,432 +48,35 @@ public class NormalizedNodeOutputStreamWriter implements NormalizedNodeDataOutpu
      */
     @Deprecated
     public NormalizedNodeOutputStreamWriter(final DataOutput output) {
-        this.output = Preconditions.checkNotNull(output);
-    }
-
-    private NormalizedNodeWriter normalizedNodeWriter() {
-        if(normalizedNodeWriter == null) {
-            normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(this);
-        }
-
-        return normalizedNodeWriter;
-    }
-
-    @Override
-    public void writeNormalizedNode(NormalizedNode<?, ?> node) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        normalizedNodeWriter().write(node);
-    }
-
-    private void writeSignatureMarkerAndVersionIfNeeded() throws IOException {
-        if(!wroteSignatureMarker) {
-            output.writeByte(TokenTypes.SIGNATURE_MARKER);
-            output.writeShort(TokenTypes.LITHIUM_VERSION);
-            wroteSignatureMarker = true;
-        }
-    }
-
-    @Override
-    public void leafNode(YangInstanceIdentifier.NodeIdentifier name, Object value) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Writing a new leaf node");
-        startNode(name.getNodeType(), NodeTypes.LEAF_NODE);
-
-        writeObject(value);
+        super(output);
     }
 
     @Override
-    public void startLeafSet(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new leaf set");
-
-        startNode(name.getNodeType(), NodeTypes.LEAF_SET);
-    }
-
-    @Override
-    public void leafSetEntryNode(Object value) throws IOException, IllegalArgumentException {
-        LOG.debug("Writing a new leaf set entry node");
-
-        output.writeByte(NodeTypes.LEAF_SET_ENTRY_NODE);
-        writeObject(value);
-    }
-
-    @Override
-    public void startContainerNode(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-
-        LOG.debug("Starting a new container node");
-
-        startNode(name.getNodeType(), NodeTypes.CONTAINER_NODE);
-    }
-
-    @Override
-    public void startYangModeledAnyXmlNode(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-
-        LOG.debug("Starting a new yang modeled anyXml node");
-
-        startNode(name.getNodeType(), NodeTypes.YANG_MODELED_ANY_XML_NODE);
+    protected final short streamVersion() {
+        return TokenTypes.LITHIUM_VERSION;
     }
 
     @Override
-    public void startUnkeyedList(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new unkeyed list");
-
-        startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST);
+    protected void writeQName(final QName qname) throws IOException {
+        writeString(qname.getLocalName());
+        writeString(qname.getNamespace().toString());
+        writeString(qname.getFormattedRevision());
     }
 
     @Override
-    public void startUnkeyedListItem(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalStateException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new unkeyed list item");
-
-        startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST_ITEM);
-    }
-
-    @Override
-    public void startMapNode(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new map node");
-
-        startNode(name.getNodeType(), NodeTypes.MAP_NODE);
-    }
-
-    @Override
-    public void startMapEntryNode(YangInstanceIdentifier.NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(identifier, "Node identifier should not be null");
-        LOG.debug("Starting a new map entry node");
-        startNode(identifier.getNodeType(), NodeTypes.MAP_ENTRY_NODE);
-
-        writeKeyValueMap(identifier.getKeyValues());
-
-    }
-
-    @Override
-    public void startOrderedMapNode(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new ordered map node");
-
-        startNode(name.getNodeType(), NodeTypes.ORDERED_MAP_NODE);
-    }
-
-    @Override
-    public void startChoiceNode(YangInstanceIdentifier.NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Starting a new choice node");
-
-        startNode(name.getNodeType(), NodeTypes.CHOICE_NODE);
-    }
-
-    @Override
-    public void startAugmentationNode(YangInstanceIdentifier.AugmentationIdentifier identifier) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(identifier, "Node identifier should not be null");
-        LOG.debug("Starting a new augmentation node");
-
-        output.writeByte(NodeTypes.AUGMENTATION_NODE);
-        writeQNameSet(identifier.getPossibleChildNames());
-    }
-
-    @Override
-    public void anyxmlNode(YangInstanceIdentifier.NodeIdentifier name, Object value) throws IOException, IllegalArgumentException {
-        Preconditions.checkNotNull(name, "Node identifier should not be null");
-        LOG.debug("Writing a new xml node");
-
-        startNode(name.getNodeType(), NodeTypes.ANY_XML_NODE);
-
-        writeObject(value);
-    }
-
-    @Override
-    public void endNode() throws IOException, IllegalStateException {
-        LOG.debug("Ending the node");
-
-        output.writeByte(NodeTypes.END_NODE);
-    }
-
-    @Override
-    public void close() throws IOException {
-        flush();
-    }
-
-    @Override
-    public void flush() throws IOException {
-        if (output instanceof OutputStream) {
-            ((OutputStream)output).flush();
-        }
-    }
-
-    private void startNode(final QName qName, byte nodeType) throws IOException {
-
-        Preconditions.checkNotNull(qName, "QName of node identifier should not be null.");
-
-        writeSignatureMarkerAndVersionIfNeeded();
-
-        // First write the type of node
-        output.writeByte(nodeType);
-        // Write Start Tag
-        writeQName(qName);
-    }
-
-    private void writeQName(QName qName) throws IOException {
-
-        writeCodedString(qName.getLocalName());
-        writeCodedString(qName.getNamespace().toString());
-        writeCodedString(qName.getFormattedRevision());
-    }
-
-    private void writeCodedString(String key) throws IOException {
-        Integer value = stringCodeMap.get(key);
-        if(value != null) {
-            output.writeByte(TokenTypes.IS_CODE_VALUE);
-            output.writeInt(value);
-        } else {
-            if(key != null) {
-                output.writeByte(TokenTypes.IS_STRING_VALUE);
-                stringCodeMap.put(key, Integer.valueOf(stringCodeMap.size()));
-                output.writeUTF(key);
+    protected void writeString(final String string) throws IOException {
+        if (string != null) {
+            final Integer value = stringCodeMap.get(string);
+            if (value == null) {
+                stringCodeMap.put(string, stringCodeMap.size());
+                writeByte(TokenTypes.IS_STRING_VALUE);
+                writeUTF(string);
             } else {
-                output.writeByte(TokenTypes.IS_NULL_VALUE);
-            }
-        }
-    }
-
-    private void writeObjSet(Set<?> set) throws IOException {
-        if(!set.isEmpty()){
-            output.writeInt(set.size());
-            for(Object o : set){
-                if(o instanceof String){
-                    writeCodedString(o.toString());
-                } else {
-                    throw new IllegalArgumentException("Expected value type to be String but was : " +
-                        o.toString());
-                }
-            }
-        } else {
-            output.writeInt(0);
-        }
-    }
-
-    @Override
-    public void writeYangInstanceIdentifier(YangInstanceIdentifier identifier) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        writeYangInstanceIdentifierInternal(identifier);
-    }
-
-    private void writeYangInstanceIdentifierInternal(YangInstanceIdentifier identifier) throws IOException {
-        Collection<YangInstanceIdentifier.PathArgument> pathArguments = identifier.getPathArguments();
-        output.writeInt(pathArguments.size());
-
-        for(YangInstanceIdentifier.PathArgument pathArgument : pathArguments) {
-            writePathArgument(pathArgument);
-        }
-    }
-
-    @Override
-    public void writePathArgument(YangInstanceIdentifier.PathArgument pathArgument) throws IOException {
-
-        byte type = PathArgumentTypes.getSerializablePathArgumentType(pathArgument);
-
-        output.writeByte(type);
-
-        switch(type) {
-            case PathArgumentTypes.NODE_IDENTIFIER:
-
-                YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
-                    (YangInstanceIdentifier.NodeIdentifier) pathArgument;
-
-                writeQName(nodeIdentifier.getNodeType());
-                break;
-
-            case PathArgumentTypes.NODE_IDENTIFIER_WITH_PREDICATES:
-
-                YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
-                    (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
-                writeQName(nodeIdentifierWithPredicates.getNodeType());
-
-                writeKeyValueMap(nodeIdentifierWithPredicates.getKeyValues());
-                break;
-
-            case PathArgumentTypes.NODE_IDENTIFIER_WITH_VALUE :
-
-                YangInstanceIdentifier.NodeWithValue nodeWithValue =
-                    (YangInstanceIdentifier.NodeWithValue) pathArgument;
-
-                writeQName(nodeWithValue.getNodeType());
-                writeObject(nodeWithValue.getValue());
-                break;
-
-            case PathArgumentTypes.AUGMENTATION_IDENTIFIER :
-
-                YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier =
-                    (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
-
-                // No Qname in augmentation identifier
-                writeQNameSet(augmentationIdentifier.getPossibleChildNames());
-                break;
-            default :
-                throw new IllegalStateException("Unknown node identifier type is found : " + pathArgument.getClass().toString() );
-        }
-    }
-
-    private void writeKeyValueMap(Map<QName, Object> keyValueMap) throws IOException {
-        if(keyValueMap != null && !keyValueMap.isEmpty()) {
-            output.writeInt(keyValueMap.size());
-            Set<QName> qNameSet = keyValueMap.keySet();
-
-            for(QName qName : qNameSet) {
-                writeQName(qName);
-                writeObject(keyValueMap.get(qName));
+                writeByte(TokenTypes.IS_CODE_VALUE);
+                writeInt(value);
             }
         } else {
-            output.writeInt(0);
+            writeByte(TokenTypes.IS_NULL_VALUE);
         }
     }
-
-    private void writeQNameSet(Set<QName> children) throws IOException {
-        // Write each child's qname separately, if list is empty send count as 0
-        if(children != null && !children.isEmpty()) {
-            output.writeInt(children.size());
-            for(QName qName : children) {
-                writeQName(qName);
-            }
-        } else {
-            LOG.debug("augmentation node does not have any child");
-            output.writeInt(0);
-        }
-    }
-
-    private void writeObject(Object value) throws IOException {
-
-        byte type = ValueTypes.getSerializableType(value);
-        // Write object type first
-        output.writeByte(type);
-
-        switch(type) {
-            case ValueTypes.BOOL_TYPE:
-                output.writeBoolean((Boolean) value);
-                break;
-            case ValueTypes.QNAME_TYPE:
-                writeQName((QName) value);
-                break;
-            case ValueTypes.INT_TYPE:
-                output.writeInt((Integer) value);
-                break;
-            case ValueTypes.BYTE_TYPE:
-                output.writeByte((Byte) value);
-                break;
-            case ValueTypes.LONG_TYPE:
-                output.writeLong((Long) value);
-                break;
-            case ValueTypes.SHORT_TYPE:
-                output.writeShort((Short) value);
-                break;
-            case ValueTypes.BITS_TYPE:
-                writeObjSet((Set<?>) value);
-                break;
-            case ValueTypes.BINARY_TYPE:
-                byte[] bytes = (byte[]) value;
-                output.writeInt(bytes.length);
-                output.write(bytes);
-                break;
-            case ValueTypes.YANG_IDENTIFIER_TYPE:
-                writeYangInstanceIdentifierInternal((YangInstanceIdentifier) value);
-                break;
-            case ValueTypes.NULL_TYPE :
-                break;
-            case ValueTypes.STRING_BYTES_TYPE:
-                final byte[] valueBytes = value.toString().getBytes(StandardCharsets.UTF_8);
-                output.writeInt(valueBytes.length);
-                output.write(valueBytes);
-                break;
-            default:
-                output.writeUTF(value.toString());
-                break;
-        }
-    }
-
-    @Override
-    public void write(int b) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.write(b);
-    }
-
-    @Override
-    public void write(byte[] b) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.write(b);
-    }
-
-    @Override
-    public void write(byte[] b, int off, int len) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.write(b, off, len);
-    }
-
-    @Override
-    public void writeBoolean(boolean v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeBoolean(v);
-    }
-
-    @Override
-    public void writeByte(int v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeByte(v);
-    }
-
-    @Override
-    public void writeShort(int v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeShort(v);
-    }
-
-    @Override
-    public void writeChar(int v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeChar(v);
-    }
-
-    @Override
-    public void writeInt(int v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeInt(v);
-    }
-
-    @Override
-    public void writeLong(long v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeLong(v);
-    }
-
-    @Override
-    public void writeFloat(float v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeFloat(v);
-    }
-
-    @Override
-    public void writeDouble(double v) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeDouble(v);
-    }
-
-    @Override
-    public void writeBytes(String s) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeBytes(s);
-    }
-
-    @Override
-    public void writeChars(String s) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeChars(s);
-    }
-
-    @Override
-    public void writeUTF(String s) throws IOException {
-        writeSignatureMarkerAndVersionIfNeeded();
-        output.writeUTF(s);
-    }
 }