From 09419e51e2e0b771b1ae013bb4c8bdf7a4f984eb Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 8 Dec 2015 14:02:50 +0100 Subject: [PATCH] BUG-4626: create AbstractNormalizedNodeDataOutput Create an internal NormalizedNodeDataOutput implementation for reuse of code between stream versions. Change-Id: I60e68fe150ba49d37a6821b057b9ef93a8e600e5 Signed-off-by: Robert Varga --- .../AbstractNormalizedNodeDataOutput.java | 437 +++++++++++++++++ .../stream/NormalizedNodeInputOutput.java | 15 +- .../NormalizedNodeInputStreamReader.java | 14 +- .../NormalizedNodeOutputStreamWriter.java | 461 +----------------- 4 files changed, 483 insertions(+), 444 deletions(-) create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.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 index 0000000000..f8ea298458 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/AbstractNormalizedNodeDataOutput.java @@ -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 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 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 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; + } + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java index cb84ef8810..5b93b274e0 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java @@ -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 { diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java index 9f6d39aa19..e1cb4b4c53 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java @@ -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); } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java index 4736773963..60250ffefd 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java @@ -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 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 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 keyValueMap) throws IOException { - if(keyValueMap != null && !keyValueMap.isEmpty()) { - output.writeInt(keyValueMap.size()); - Set 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 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); - } } -- 2.36.6