From 3218b86835d963705ab13d039ab53c388313d30c Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 5 Oct 2023 17:17:29 +0200 Subject: [PATCH] Remove support for inputs older than Magnesium We have a number of obsolete formats here, which are not efficient or tested. Eliminate LITHIUM,NEON_SR2 and SODIUM_SR1 support. JIRA: YANGTOOLS-1548 Change-Id: I973916d2ffb25e219380c854dcbe2d86d0b60337 Signed-off-by: Robert Varga --- .../binfmt/AbstractLithiumDataInput.java | 390 --------- .../binfmt/AbstractMagnesiumDataInput.java | 810 ------------------ .../yang/data/codec/binfmt/LithiumNode.java | 35 - ...ithiumNormalizedNodeInputStreamReader.java | 49 -- .../codec/binfmt/LithiumPathArgument.java | 36 - .../yang/data/codec/binfmt/LithiumTokens.java | 31 - .../yang/data/codec/binfmt/LithiumValue.java | 36 - .../data/codec/binfmt/MagnesiumDataInput.java | 791 ++++++++++++++++- ...eonSR2NormalizedNodeInputStreamReader.java | 153 ---- .../yang/data/codec/binfmt/NeonSR2Tokens.java | 25 - .../binfmt/NormalizedNodeStreamVersion.java | 63 -- .../data/codec/binfmt/SodiumSR1DataInput.java | 30 - .../yang/data/codec/binfmt/TokenTypes.java | 23 +- .../VersionedNormalizedNodeDataInput.java | 3 - 14 files changed, 797 insertions(+), 1678 deletions(-) delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java delete mode 100755 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java delete mode 100644 codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java deleted file mode 100644 index 9953d027e6..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (c) 2014, 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 com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.ImmutableSet; -import java.io.DataInput; -import java.io.IOException; -import java.io.StringReader; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.dom.DOMSource; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.yangtools.concepts.Either; -import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate; -import org.opendaylight.yangtools.yang.common.Decimal64; -import org.opendaylight.yangtools.yang.common.Empty; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * NormalizedNodeInputStreamReader reads the byte stream and constructs the normalized node including its children - * nodes. This process goes in recursive manner, where each NodeTypes object signifies the start of the object, except - * END_NODE. If a node can have children, then that node's end is calculated based on appearance of END_NODE. - */ -abstract class AbstractLithiumDataInput extends AbstractLegacyDataInput { - private static final Logger LOG = LoggerFactory.getLogger(AbstractLithiumDataInput.class); - - private final List codedStringMap = new ArrayList<>(); - - private QName lastLeafSetQName; - - AbstractLithiumDataInput(final DataInput input) { - super(input); - } - - @Override - public final void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException { - streamNormalizedNode(requireNonNull(writer), input.readByte()); - } - - private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final byte nodeType) throws IOException { - switch (nodeType) { - case LithiumNode.ANY_XML_NODE -> streamAnyxml(writer); - case LithiumNode.AUGMENTATION_NODE -> streamAugmentation(writer); - case LithiumNode.CHOICE_NODE -> streamChoice(writer); - case LithiumNode.CONTAINER_NODE -> streamContainer(writer); - case LithiumNode.LEAF_NODE -> streamLeaf(writer); - case LithiumNode.LEAF_SET -> streamLeafSet(writer); - case LithiumNode.ORDERED_LEAF_SET -> streamOrderedLeafSet(writer); - case LithiumNode.LEAF_SET_ENTRY_NODE -> streamLeafSetEntry(writer); - case LithiumNode.MAP_ENTRY_NODE -> streamMapEntry(writer); - case LithiumNode.MAP_NODE -> streamMap(writer); - case LithiumNode.ORDERED_MAP_NODE -> streamOrderedMap(writer); - case LithiumNode.UNKEYED_LIST -> streamUnkeyedList(writer); - case LithiumNode.UNKEYED_LIST_ITEM -> streamUnkeyedListItem(writer); - default -> throw new InvalidNormalizedNodeStreamException("Unexpected node " + nodeType); - } - } - - private void streamAnyxml(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming anyxml node {}", identifier); - - final DOMSource value = readDOMSource(); - if (writer.startAnyxmlNode(identifier, DOMSource.class)) { - writer.domSourceValue(value); - writer.endNode(); - } - } - - private void streamAugmentation(final NormalizedNodeStreamWriter writer) throws IOException { - final var augIdentifier = readAugmentationIdentifier(); - LOG.trace("Streaming augmentation node {}", augIdentifier); - for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) { - streamNormalizedNode(writer, nodeType); - } - } - - private void streamChoice(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming choice node {}", identifier); - writer.startChoiceNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void streamContainer(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming container node {}", identifier); - writer.startContainerNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void streamLeaf(final NormalizedNodeStreamWriter writer) throws IOException { - startLeaf(writer); - endLeaf(writer, readObject()); - } - - // Leaf inside a MapEntryNode, it can potentially be a key leaf, in which case we want to de-duplicate values. - private void streamLeaf(final NormalizedNodeStreamWriter writer, final NodeIdentifierWithPredicates entryId) - throws IOException { - final NodeIdentifier identifier = startLeaf(writer); - final Object value = readObject(); - final Object entryValue = entryId.getValue(identifier.getNodeType()); - endLeaf(writer, entryValue == null ? value : entryValue); - } - - private NodeIdentifier startLeaf(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming leaf node {}", identifier); - writer.startLeafNode(identifier); - return identifier; - } - - private static void endLeaf(final NormalizedNodeStreamWriter writer, final Object value) throws IOException { - writer.scalarValue(value); - writer.endNode(); - } - - private void streamLeafSet(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming leaf set node {}", identifier); - writer.startLeafSet(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamLeafSet(writer, identifier); - } - - private void streamOrderedLeafSet(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming ordered leaf set node {}", identifier); - writer.startOrderedLeafSet(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamLeafSet(writer, identifier); - } - - private void commonStreamLeafSet(final NormalizedNodeStreamWriter writer, final NodeIdentifier identifier) - throws IOException { - lastLeafSetQName = identifier.getNodeType(); - try { - commonStreamContainer(writer); - } finally { - // Make sure we never leak this - lastLeafSetQName = null; - } - } - - private void streamLeafSetEntry(final NormalizedNodeStreamWriter writer) throws IOException { - final QName name = lastLeafSetQName != null ? lastLeafSetQName : readQName(); - final Object value = readObject(); - final NodeWithValue leafIdentifier = new NodeWithValue<>(name, value); - LOG.trace("Streaming leaf set entry node {}, value {}", leafIdentifier, value); - writer.startLeafSetEntryNode(leafIdentifier); - writer.scalarValue(value); - writer.endNode(); - } - - private void streamMap(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming map node {}", identifier); - writer.startMapNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void streamOrderedMap(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming ordered map node {}", identifier); - writer.startOrderedMapNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void streamMapEntry(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifierWithPredicates entryIdentifier = readNormalizedNodeWithPredicates(); - LOG.trace("Streaming map entry node {}", entryIdentifier); - writer.startMapEntryNode(entryIdentifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - - // Same loop as commonStreamContainer(), but ... - for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) { - if (nodeType == LithiumNode.LEAF_NODE) { - // ... leaf nodes may need de-duplication - streamLeaf(writer, entryIdentifier); - } else { - streamNormalizedNode(writer, nodeType); - } - } - writer.endNode(); - } - - private void streamUnkeyedList(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming unkeyed list node {}", identifier); - writer.startUnkeyedList(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void streamUnkeyedListItem(final NormalizedNodeStreamWriter writer) throws IOException { - final NodeIdentifier identifier = readNodeIdentifier(); - LOG.trace("Streaming unkeyed list item node {}", identifier); - writer.startUnkeyedListItem(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE); - commonStreamContainer(writer); - } - - private void commonStreamContainer(final NormalizedNodeStreamWriter writer) throws IOException { - for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) { - streamNormalizedNode(writer, nodeType); - } - writer.endNode(); - } - - private DOMSource readDOMSource() throws IOException { - String xml = readObject().toString(); - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - Element node = factory.newDocumentBuilder().parse( - new InputSource(new StringReader(xml))).getDocumentElement(); - return new DOMSource(node); - } catch (SAXException | ParserConfigurationException e) { - throw new IOException("Error parsing XML: " + xml, e); - } - } - - final QName defaultReadQName() throws IOException { - // Read in the same sequence of writing - String localName = readCodedString(); - String namespace = readCodedString(); - String revision = Strings.emptyToNull(readCodedString()); - - return QNameFactory.create(localName, namespace, revision); - } - - final String readCodedString() throws IOException { - final byte valueType = input.readByte(); - return switch (valueType) { - case LithiumTokens.IS_NULL_VALUE -> null; - case LithiumTokens.IS_CODE_VALUE -> { - final int code = input.readInt(); - try { - yield codedStringMap.get(code); - } catch (IndexOutOfBoundsException e) { - throw new IOException("String code " + code + " was not found", e); - } - } - case LithiumTokens.IS_STRING_VALUE -> { - final String value = input.readUTF().intern(); - codedStringMap.add(value); - yield value; - } - default -> throw new IOException("Unhandled string value type " + valueType); - }; - } - - private ImmutableSet readQNameSet() throws IOException { - // Read the children count - final int count = input.readInt(); - final var children = ImmutableSet.builderWithExpectedSize(count); - for (int i = 0; i < count; i++) { - children.add(readQName()); - } - return children.build(); - } - - abstract @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException; - - abstract @NonNull NodeIdentifier readNodeIdentifier() throws IOException; - - final @NonNull LegacyAugmentationIdentifier defaultReadAugmentationIdentifier() throws IOException { - return new LegacyAugmentationIdentifier(readQNameSet()); - } - - private @NonNull NodeIdentifierWithPredicates readNormalizedNodeWithPredicates() throws IOException { - final QName qname = readQName(); - final int count = input.readInt(); - switch (count) { - case 0: - return NodeIdentifierWithPredicates.of(qname); - case 1: - return NodeIdentifierWithPredicates.of(qname, readQName(), readObject()); - default: - // ImmutableList is used by ImmutableOffsetMapTemplate for lookups, hence we use that. - final Builder keys = ImmutableList.builderWithExpectedSize(count); - final Object[] values = new Object[count]; - for (int i = 0; i < count; i++) { - keys.add(readQName()); - values[i] = readObject(); - } - - return NodeIdentifierWithPredicates.of(qname, ImmutableOffsetMapTemplate.ordered(keys.build()) - .instantiateWithValues(values)); - } - } - - private Object readObject() throws IOException { - byte objectType = input.readByte(); - return switch (objectType) { - case LithiumValue.BITS_TYPE -> readObjSet(); - case LithiumValue.BOOL_TYPE -> input.readBoolean(); - case LithiumValue.BYTE_TYPE -> input.readByte(); - case LithiumValue.INT_TYPE -> input.readInt(); - case LithiumValue.LONG_TYPE -> input.readLong(); - case LithiumValue.QNAME_TYPE -> readQName(); - case LithiumValue.SHORT_TYPE -> input.readShort(); - case LithiumValue.STRING_TYPE -> input.readUTF(); - case LithiumValue.STRING_BYTES_TYPE -> readStringBytes(); - case LithiumValue.BIG_DECIMAL_TYPE -> Decimal64.valueOf(input.readUTF()); - case LithiumValue.BIG_INTEGER_TYPE -> new BigInteger(input.readUTF()); - case LithiumValue.BINARY_TYPE -> { - byte[] bytes = new byte[input.readInt()]; - input.readFully(bytes); - yield bytes; - } - case LithiumValue.YANG_IDENTIFIER_TYPE -> readYangInstanceIdentifierInternal(); - case LithiumValue.EMPTY_TYPE, LithiumValue.NULL_TYPE -> - // Leaf nodes no longer allow null values and thus we no longer emit null values. Previously, the "empty" - // yang type was represented as null so we translate an incoming null value to Empty. It was possible for - // a BI user to set a string leaf to null and we're rolling the dice here but the chances for that are - // very low. We'd have to know the yang type but, even if we did, we can't let a null value pass upstream - // so we'd have to drop the leaf which might cause other issues. - Empty.value(); - default -> null; - }; - } - - private String readStringBytes() throws IOException { - byte[] bytes = new byte[input.readInt()]; - input.readFully(bytes); - return new String(bytes, StandardCharsets.UTF_8); - } - - @Override - public final YangInstanceIdentifier readYangInstanceIdentifier() throws IOException { - return readYangInstanceIdentifierInternal(); - } - - private @NonNull YangInstanceIdentifier readYangInstanceIdentifierInternal() throws IOException { - int size = input.readInt(); - final Builder pathArguments = ImmutableList.builderWithExpectedSize(size); - for (int i = 0; i < size; i++) { - pathArguments.add(readPathArgument()); - } - return YangInstanceIdentifier.of(pathArguments.build()); - } - - private Set readObjSet() throws IOException { - int count = input.readInt(); - Set children = new HashSet<>(count); - for (int i = 0; i < count; i++) { - children.add(readCodedString()); - } - return children; - } - - @Override - @Deprecated(since = "11.0.0", forRemoval = true) - public final Either readLegacyPathArgument() throws IOException { - // read Type - int type = input.readByte(); - return switch (type) { - case LithiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier()); - case LithiumPathArgument.NODE_IDENTIFIER -> Either.ofFirst(readNodeIdentifier()); - case LithiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES -> - Either.ofFirst(readNormalizedNodeWithPredicates()); - case LithiumPathArgument.NODE_IDENTIFIER_WITH_VALUE -> - Either.ofFirst(new NodeWithValue<>(readQName(), readObject())); - default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument type " + type); - }; - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java deleted file mode 100644 index bc3734b971..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java +++ /dev/null @@ -1,810 +0,0 @@ -/* - * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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 com.google.common.base.Verify.verifyNotNull; -import static java.util.Objects.requireNonNull; -import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.util.concurrent.UncheckedExecutionException; -import java.io.DataInput; -import java.io.IOException; -import java.io.StringReader; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import javax.xml.transform.dom.DOMSource; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.yangtools.concepts.Either; -import org.opendaylight.yangtools.util.xml.UntrustedXML; -import org.opendaylight.yangtools.yang.common.Decimal64; -import org.opendaylight.yangtools.yang.common.Empty; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.Uint16; -import org.opendaylight.yangtools.yang.common.Uint32; -import org.opendaylight.yangtools.yang.common.Uint64; -import org.opendaylight.yangtools.yang.common.Uint8; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Abstract base class for NormalizedNodeDataInput based on {@link MagnesiumNode}, {@link MagnesiumPathArgument} and - * {@link MagnesiumValue}. - */ -abstract class AbstractMagnesiumDataInput extends AbstractLegacyDataInput { - private static final Logger LOG = LoggerFactory.getLogger(AbstractMagnesiumDataInput.class); - - // Known singleton objects - private static final @NonNull Byte INT8_0 = 0; - private static final @NonNull Short INT16_0 = 0; - private static final @NonNull Integer INT32_0 = 0; - private static final @NonNull Long INT64_0 = 0L; - private static final byte @NonNull[] BINARY_0 = new byte[0]; - private static final @NonNull LegacyAugmentationIdentifier EMPTY_AID = - new LegacyAugmentationIdentifier(ImmutableSet.of()); - - private final List codedAugments = new ArrayList<>(); - private final List codedNodeIdentifiers = new ArrayList<>(); - private final List codedModules = new ArrayList<>(); - private final List codedStrings = new ArrayList<>(); - - AbstractMagnesiumDataInput(final DataInput input) { - super(input); - } - - @Override - public final void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException { - streamNormalizedNode(requireNonNull(writer), null, input.readByte()); - } - - private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final Object parent, - final byte nodeHeader) throws IOException { - switch (nodeHeader & MagnesiumNode.TYPE_MASK) { - case MagnesiumNode.NODE_LEAF: - streamLeaf(writer, parent, nodeHeader); - break; - case MagnesiumNode.NODE_CONTAINER: - streamContainer(writer, nodeHeader); - break; - case MagnesiumNode.NODE_LIST: - streamList(writer, nodeHeader); - break; - case MagnesiumNode.NODE_MAP: - streamMap(writer, nodeHeader); - break; - case MagnesiumNode.NODE_MAP_ORDERED: - streamMapOrdered(writer, nodeHeader); - break; - case MagnesiumNode.NODE_LEAFSET: - streamLeafset(writer, nodeHeader); - break; - case MagnesiumNode.NODE_LEAFSET_ORDERED: - streamLeafsetOrdered(writer, nodeHeader); - break; - case MagnesiumNode.NODE_CHOICE: - streamChoice(writer, nodeHeader); - break; - case MagnesiumNode.NODE_AUGMENTATION: - streamAugmentation(writer, nodeHeader); - break; - case MagnesiumNode.NODE_ANYXML: - streamAnyxml(writer, nodeHeader); - break; - case MagnesiumNode.NODE_LIST_ENTRY: - streamListEntry(writer, parent, nodeHeader); - break; - case MagnesiumNode.NODE_LEAFSET_ENTRY: - streamLeafsetEntry(writer, parent, nodeHeader); - break; - case MagnesiumNode.NODE_MAP_ENTRY: - streamMapEntry(writer, parent, nodeHeader); - break; - default: - throw new InvalidNormalizedNodeStreamException("Unexpected node header " + nodeHeader); - } - } - - private void streamAnyxml(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming anyxml node {}", identifier); - - final DOMSource value = readDOMSource(); - if (writer.startAnyxmlNode(identifier, DOMSource.class)) { - writer.domSourceValue(value); - writer.endNode(); - } - } - - private void streamAugmentation(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final var augIdentifier = decodeAugmentationIdentifier(nodeHeader); - LOG.trace("Streaming augmentation node {}", augIdentifier); - for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) { - streamNormalizedNode(writer, augIdentifier, nodeType); - } - } - - private void streamChoice(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming choice node {}", identifier); - writer.startChoiceNode(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamContainer(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming container node {}", identifier); - writer.startContainerNode(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamLeaf(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) - throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming leaf node {}", identifier); - writer.startLeafNode(identifier); - - final Object value; - if ((nodeHeader & MagnesiumNode.PREDICATE_ONE) == MagnesiumNode.PREDICATE_ONE) { - if (!(parent instanceof NodeIdentifierWithPredicates nip)) { - throw new InvalidNormalizedNodeStreamException("Invalid predicate leaf " + identifier + " in parent " - + parent); - } - - value = nip.getValue(identifier.getNodeType()); - if (value == null) { - throw new InvalidNormalizedNodeStreamException("Failed to find predicate leaf " + identifier - + " in parent " + parent); - } - } else { - value = readLeafValue(); - } - - writer.scalarValue(value); - writer.endNode(); - } - - private void streamLeafset(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming leaf set node {}", identifier); - writer.startLeafSet(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamLeafsetOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) - throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming ordered leaf set node {}", identifier); - writer.startOrderedLeafSet(identifier, UNKNOWN_SIZE); - - commonStreamContainer(writer, identifier); - } - - private void streamLeafsetEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) - throws IOException { - final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent); - final Object value = readLeafValue(); - final NodeWithValue leafIdentifier = new NodeWithValue<>(nodeId.getNodeType(), value); - LOG.trace("Streaming leaf set entry node {}", leafIdentifier); - writer.startLeafSetEntryNode(leafIdentifier); - writer.scalarValue(value); - writer.endNode(); - } - - private void streamList(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - writer.startUnkeyedList(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamListEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) - throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader, parent); - LOG.trace("Streaming unkeyed list item node {}", identifier); - writer.startUnkeyedListItem(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamMap(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming map node {}", identifier); - writer.startMapNode(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamMapOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { - final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); - LOG.trace("Streaming ordered map node {}", identifier); - writer.startOrderedMapNode(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void streamMapEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) - throws IOException { - final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent); - - final int size = switch (mask(nodeHeader, MagnesiumNode.PREDICATE_MASK)) { - case MagnesiumNode.PREDICATE_ZERO -> 0; - case MagnesiumNode.PREDICATE_ONE -> 1; - case MagnesiumNode.PREDICATE_1B -> input.readUnsignedByte(); - case MagnesiumNode.PREDICATE_4B -> input.readInt(); - default -> - // ISE on purpose: this should never ever happen - throw new IllegalStateException("Failed to decode NodeIdentifierWithPredicates size from header " - + nodeHeader); - }; - final NodeIdentifierWithPredicates identifier = readNodeIdentifierWithPredicates(nodeId.getNodeType(), size); - LOG.trace("Streaming map entry node {}", identifier); - writer.startMapEntryNode(identifier, UNKNOWN_SIZE); - commonStreamContainer(writer, identifier); - } - - private void commonStreamContainer(final NormalizedNodeStreamWriter writer, final PathArgument parent) - throws IOException { - for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) { - streamNormalizedNode(writer, parent, nodeType); - } - writer.endNode(); - } - - private @NonNull NodeIdentifier decodeNodeIdentifier() throws IOException { - final QNameModule module = decodeQNameModule(); - final String localName = readRefString(); - final NodeIdentifier nodeId; - try { - nodeId = QNameFactory.getNodeIdentifier(module, localName); - } catch (ExecutionException e) { - throw new InvalidNormalizedNodeStreamException("Illegal QName module=" + module + " localName=" - + localName, e); - } - - codedNodeIdentifiers.add(nodeId); - return nodeId; - } - - private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader) throws IOException { - return decodeNodeIdentifier(nodeHeader, null); - } - - private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader, final Object parent) throws IOException { - final int index; - switch (nodeHeader & MagnesiumNode.ADDR_MASK) { - case MagnesiumNode.ADDR_DEFINE: - return readNodeIdentifier(); - case MagnesiumNode.ADDR_LOOKUP_1B: - index = input.readUnsignedByte(); - break; - case MagnesiumNode.ADDR_LOOKUP_4B: - index = input.readInt(); - break; - case MagnesiumNode.ADDR_PARENT: - if (parent instanceof NodeIdentifier nid) { - return nid; - } - throw new InvalidNormalizedNodeStreamException("Invalid node identifier reference to parent " + parent); - default: - throw new InvalidNormalizedNodeStreamException("Unexpected node identifier addressing in header " - + nodeHeader); - } - - try { - return codedNodeIdentifiers.get(index); - } catch (IndexOutOfBoundsException e) { - throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e); - } - } - - private LegacyAugmentationIdentifier decodeAugmentationIdentifier(final byte nodeHeader) throws IOException { - final int index; - switch (nodeHeader & MagnesiumNode.ADDR_MASK) { - case MagnesiumNode.ADDR_DEFINE: - return readAugmentationIdentifier(); - case MagnesiumNode.ADDR_LOOKUP_1B: - index = input.readUnsignedByte(); - break; - case MagnesiumNode.ADDR_LOOKUP_4B: - index = input.readInt(); - break; - default: - throw new InvalidNormalizedNodeStreamException( - "Unexpected augmentation identifier addressing in header " + nodeHeader); - } - - try { - return codedAugments.get(index); - } catch (IndexOutOfBoundsException e) { - throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier reference " + index, e); - } - } - - @Override - public final YangInstanceIdentifier readYangInstanceIdentifier() throws IOException { - final byte type = input.readByte(); - if (type == MagnesiumValue.YIID) { - return readYangInstanceIdentifier(input.readInt()); - } else if (type >= MagnesiumValue.YIID_0) { - // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31' - return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0); - } else { - throw new InvalidNormalizedNodeStreamException("Unexpected YangInstanceIdentifier type " + type); - } - } - - private @NonNull YangInstanceIdentifier readYangInstanceIdentifier(final int size) throws IOException { - if (size > 0) { - final Builder builder = ImmutableList.builderWithExpectedSize(size); - for (int i = 0; i < size; ++i) { - builder.add(readPathArgument()); - } - return YangInstanceIdentifier.of(builder.build()); - } else if (size == 0) { - return YangInstanceIdentifier.of(); - } else { - throw new InvalidNormalizedNodeStreamException("Invalid YangInstanceIdentifier size " + size); - } - } - - @Override - public final QName readQName() throws IOException { - final byte type = input.readByte(); - return switch (type) { - case MagnesiumValue.QNAME -> decodeQName(); - case MagnesiumValue.QNAME_REF_1B -> decodeQNameRef1(); - case MagnesiumValue.QNAME_REF_2B -> decodeQNameRef2(); - case MagnesiumValue.QNAME_REF_4B -> decodeQNameRef4(); - default -> throw new InvalidNormalizedNodeStreamException("Unexpected QName type " + type); - }; - } - - @Override - @Deprecated(since = "11.0.0", forRemoval = true) - public final Either readLegacyPathArgument() throws IOException { - final byte header = input.readByte(); - return switch (header & MagnesiumPathArgument.TYPE_MASK) { - case MagnesiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier(header)); - case MagnesiumPathArgument.NODE_IDENTIFIER -> { - verifyPathIdentifierOnly(header); - yield Either.ofFirst(readNodeIdentifier(header)); - } - case MagnesiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES -> - Either.ofFirst(readNodeIdentifierWithPredicates(header)); - case MagnesiumPathArgument.NODE_WITH_VALUE -> { - verifyPathIdentifierOnly(header); - yield Either.ofFirst(readNodeWithValue(header)); - } - case MagnesiumPathArgument.MOUNTPOINT_IDENTIFIER -> { - verifyPathIdentifierOnly(header); - yield Either.ofSecond(new LegacyMountPointIdentifier(readNodeIdentifier(header).getNodeType())); - } - default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument header " + header); - }; - } - - private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException { - final var result = readAugmentationIdentifier(input.readInt()); - codedAugments.add(result); - return result; - } - - private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final byte header) throws IOException { - final byte count = mask(header, MagnesiumPathArgument.AID_COUNT_MASK); - return switch (count) { - case MagnesiumPathArgument.AID_COUNT_1B -> readAugmentationIdentifier(input.readUnsignedByte()); - case MagnesiumPathArgument.AID_COUNT_2B -> readAugmentationIdentifier(input.readUnsignedShort()); - case MagnesiumPathArgument.AID_COUNT_4B -> readAugmentationIdentifier(input.readInt()); - default -> readAugmentationIdentifier(rshift(count, MagnesiumPathArgument.AID_COUNT_SHIFT)); - }; - } - - private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final int size) throws IOException { - if (size > 0) { - final var qnames = ImmutableSet.builderWithExpectedSize(size); - for (int i = 0; i < size; ++i) { - qnames.add(readQName()); - } - return new LegacyAugmentationIdentifier(qnames.build()); - } else if (size == 0) { - return EMPTY_AID; - } else { - throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier size " + size); - } - } - - private @NonNull NodeIdentifier readNodeIdentifier() throws IOException { - return decodeNodeIdentifier(); - } - - private @NonNull NodeIdentifier readNodeIdentifier(final byte header) throws IOException { - return switch (header & MagnesiumPathArgument.QNAME_MASK) { - case MagnesiumPathArgument.QNAME_DEF -> decodeNodeIdentifier(); - case MagnesiumPathArgument.QNAME_REF_1B -> decodeNodeIdentifierRef1(); - case MagnesiumPathArgument.QNAME_REF_2B -> decodeNodeIdentifierRef2(); - case MagnesiumPathArgument.QNAME_REF_4B -> decodeNodeIdentifierRef4(); - default -> throw new InvalidNormalizedNodeStreamException("Invalid QName coding in " + header); - }; - } - - private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header) - throws IOException { - final QName qname = readNodeIdentifier(header).getNodeType(); - return switch (mask(header, MagnesiumPathArgument.SIZE_MASK)) { - case MagnesiumPathArgument.SIZE_1B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedByte()); - case MagnesiumPathArgument.SIZE_2B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedShort()); - case MagnesiumPathArgument.SIZE_4B -> readNodeIdentifierWithPredicates(qname, input.readInt()); - default -> readNodeIdentifierWithPredicates(qname, rshift(header, MagnesiumPathArgument.SIZE_SHIFT)); - }; - } - - private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final QName qname, final int size) - throws IOException { - if (size == 1) { - return NodeIdentifierWithPredicates.of(qname, readQName(), readLeafValue()); - } else if (size > 1) { - final ImmutableMap.Builder builder = ImmutableMap.builderWithExpectedSize(size); - for (int i = 0; i < size; ++i) { - builder.put(readQName(), readLeafValue()); - } - return NodeIdentifierWithPredicates.of(qname, builder.build()); - } else if (size == 0) { - return NodeIdentifierWithPredicates.of(qname); - } else { - throw new InvalidNormalizedNodeStreamException("Invalid predicate count " + size); - } - } - - private @NonNull NodeWithValue readNodeWithValue(final byte header) throws IOException { - final QName qname = readNodeIdentifier(header).getNodeType(); - return new NodeWithValue<>(qname, readLeafValue()); - } - - private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException { - if (mask(header, MagnesiumPathArgument.SIZE_MASK) != 0) { - throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header); - } - } - - private @NonNull NodeIdentifier decodeNodeIdentifierRef1() throws IOException { - return lookupNodeIdentifier(input.readUnsignedByte()); - } - - private @NonNull NodeIdentifier decodeNodeIdentifierRef2() throws IOException { - return lookupNodeIdentifier(input.readUnsignedShort() + 256); - } - - private @NonNull NodeIdentifier decodeNodeIdentifierRef4() throws IOException { - return lookupNodeIdentifier(input.readInt()); - } - - private @NonNull QName decodeQName() throws IOException { - return decodeNodeIdentifier().getNodeType(); - } - - private @NonNull QName decodeQNameRef1() throws IOException { - return lookupQName(input.readUnsignedByte()); - } - - private @NonNull QName decodeQNameRef2() throws IOException { - return lookupQName(input.readUnsignedShort() + 256); - } - - private @NonNull QName decodeQNameRef4() throws IOException { - return lookupQName(input.readInt()); - } - - private @NonNull QNameModule decodeQNameModule() throws IOException { - final byte type = input.readByte(); - final int index; - switch (type) { - case MagnesiumValue.MODREF_1B: - index = input.readUnsignedByte(); - break; - case MagnesiumValue.MODREF_2B: - index = input.readUnsignedShort() + 256; - break; - case MagnesiumValue.MODREF_4B: - index = input.readInt(); - break; - default: - return decodeQNameModuleDef(type); - } - - try { - return codedModules.get(index); - } catch (IndexOutOfBoundsException e) { - throw new InvalidNormalizedNodeStreamException("Invalid QNameModule reference " + index, e); - } - } - - // QNameModule definition, i.e. two encoded strings - private @NonNull QNameModule decodeQNameModuleDef(final byte type) throws IOException { - final String namespace = readRefString(type); - - final byte refType = input.readByte(); - final String revision = refType == MagnesiumValue.STRING_EMPTY ? null : readRefString(refType); - final QNameModule module; - try { - module = QNameFactory.createModule(namespace, revision); - } catch (UncheckedExecutionException e) { - throw new InvalidNormalizedNodeStreamException("Illegal QNameModule ns=" + namespace + " rev=" + revision, - e); - } - - codedModules.add(module); - return module; - } - - private @NonNull String readRefString() throws IOException { - return readRefString(input.readByte()); - } - - private @NonNull String readRefString(final byte type) throws IOException { - final String str; - switch (type) { - case MagnesiumValue.STRING_REF_1B: - return lookupString(input.readUnsignedByte()); - case MagnesiumValue.STRING_REF_2B: - return lookupString(input.readUnsignedShort() + 256); - case MagnesiumValue.STRING_REF_4B: - return lookupString(input.readInt()); - case MagnesiumValue.STRING_EMPTY: - return ""; - case MagnesiumValue.STRING_2B: - str = readString2(); - break; - case MagnesiumValue.STRING_4B: - str = readString4(); - break; - case MagnesiumValue.STRING_CHARS: - str = readCharsString(); - break; - case MagnesiumValue.STRING_UTF: - str = input.readUTF(); - break; - default: - throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type); - } - - // TODO: consider interning Strings -- that would help with bits, but otherwise it's probably not worth it - codedStrings.add(verifyNotNull(str)); - return str; - } - - private @NonNull String readString() throws IOException { - final byte type = input.readByte(); - return switch (type) { - case MagnesiumValue.STRING_EMPTY -> ""; - case MagnesiumValue.STRING_UTF -> input.readUTF(); - case MagnesiumValue.STRING_2B -> readString2(); - case MagnesiumValue.STRING_4B -> readString4(); - case MagnesiumValue.STRING_CHARS -> readCharsString(); - default -> throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type); - }; - } - - private @NonNull String readString2() throws IOException { - return readByteString(input.readUnsignedShort()); - } - - private @NonNull String readString4() throws IOException { - return readByteString(input.readInt()); - } - - private @NonNull String readByteString(final int size) throws IOException { - if (size > 0) { - final byte[] bytes = new byte[size]; - input.readFully(bytes); - return new String(bytes, StandardCharsets.UTF_8); - } else if (size == 0) { - return ""; - } else { - throw new InvalidNormalizedNodeStreamException("Invalid String bytes length " + size); - } - } - - private @NonNull String readCharsString() throws IOException { - final int size = input.readInt(); - if (size > 0) { - final char[] chars = new char[size]; - for (int i = 0; i < size; ++i) { - chars[i] = input.readChar(); - } - return String.valueOf(chars); - } else if (size == 0) { - return ""; - } else { - throw new InvalidNormalizedNodeStreamException("Invalid String chars length " + size); - } - } - - private @NonNull NodeIdentifier lookupNodeIdentifier(final int index) throws InvalidNormalizedNodeStreamException { - try { - return codedNodeIdentifiers.get(index); - } catch (IndexOutOfBoundsException e) { - throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e); - } - } - - private @NonNull QName lookupQName(final int index) throws InvalidNormalizedNodeStreamException { - return lookupNodeIdentifier(index).getNodeType(); - } - - private @NonNull String lookupString(final int index) throws InvalidNormalizedNodeStreamException { - try { - return codedStrings.get(index); - } catch (IndexOutOfBoundsException e) { - throw new InvalidNormalizedNodeStreamException("Invalid String reference " + index, e); - } - } - - private @NonNull DOMSource readDOMSource() throws IOException { - final String str = readString(); - try { - return new DOMSource(UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(str))) - .getDocumentElement()); - } catch (SAXException e) { - throw new IOException("Error parsing XML: " + str, e); - } - } - - private @NonNull Object readLeafValue() throws IOException { - final byte type = input.readByte(); - switch (type) { - case MagnesiumValue.BOOLEAN_FALSE: - return Boolean.FALSE; - case MagnesiumValue.BOOLEAN_TRUE: - return Boolean.TRUE; - case MagnesiumValue.EMPTY: - return Empty.value(); - case MagnesiumValue.INT8: - return input.readByte(); - case MagnesiumValue.INT8_0: - return INT8_0; - case MagnesiumValue.INT16: - return input.readShort(); - case MagnesiumValue.INT16_0: - return INT16_0; - case MagnesiumValue.INT32: - return input.readInt(); - case MagnesiumValue.INT32_0: - return INT32_0; - case MagnesiumValue.INT32_2B: - return input.readShort() & 0xFFFF; - case MagnesiumValue.INT64: - return input.readLong(); - case MagnesiumValue.INT64_0: - return INT64_0; - case MagnesiumValue.INT64_4B: - return input.readInt() & 0xFFFFFFFFL; - case MagnesiumValue.UINT8: - return Uint8.fromByteBits(input.readByte()); - case MagnesiumValue.UINT8_0: - return Uint8.ZERO; - case MagnesiumValue.UINT16: - return Uint16.fromShortBits(input.readShort()); - case MagnesiumValue.UINT16_0: - return Uint16.ZERO; - case MagnesiumValue.UINT32: - return Uint32.fromIntBits(input.readInt()); - case MagnesiumValue.UINT32_0: - return Uint32.ZERO; - case MagnesiumValue.UINT32_2B: - return Uint32.fromIntBits(input.readShort() & 0xFFFF); - case MagnesiumValue.UINT64: - return Uint64.fromLongBits(input.readLong()); - case MagnesiumValue.UINT64_0: - return Uint64.ZERO; - case MagnesiumValue.UINT64_4B: - return Uint64.fromLongBits(input.readInt() & 0xFFFFFFFFL); - case MagnesiumValue.BIGDECIMAL: - // FIXME: use string -> BigDecimal cache - return Decimal64.valueOf(input.readUTF()); - case MagnesiumValue.BIGINTEGER: - return readBigInteger(); - case MagnesiumValue.STRING_EMPTY: - return ""; - case MagnesiumValue.STRING_UTF: - return input.readUTF(); - case MagnesiumValue.STRING_2B: - return readString2(); - case MagnesiumValue.STRING_4B: - return readString4(); - case MagnesiumValue.STRING_CHARS: - return readCharsString(); - case MagnesiumValue.BINARY_0: - return BINARY_0; - case MagnesiumValue.BINARY_1B: - return readBinary(128 + input.readUnsignedByte()); - case MagnesiumValue.BINARY_2B: - return readBinary(384 + input.readUnsignedShort()); - case MagnesiumValue.BINARY_4B: - return readBinary(input.readInt()); - case MagnesiumValue.YIID_0: - return YangInstanceIdentifier.of(); - case MagnesiumValue.YIID: - return readYangInstanceIdentifier(input.readInt()); - case MagnesiumValue.QNAME: - return decodeQName(); - case MagnesiumValue.QNAME_REF_1B: - return decodeQNameRef1(); - case MagnesiumValue.QNAME_REF_2B: - return decodeQNameRef2(); - case MagnesiumValue.QNAME_REF_4B: - return decodeQNameRef4(); - case MagnesiumValue.BITS_0: - return ImmutableSet.of(); - case MagnesiumValue.BITS_1B: - return readBits(input.readUnsignedByte() + 29); - case MagnesiumValue.BITS_2B: - return readBits(input.readUnsignedShort() + 285); - case MagnesiumValue.BITS_4B: - return readBits(input.readInt()); - - default: - if (type > MagnesiumValue.BINARY_0 && type <= MagnesiumValue.BINARY_127) { - return readBinary(type - MagnesiumValue.BINARY_0); - } else if (type > MagnesiumValue.BITS_0 && type < MagnesiumValue.BITS_1B) { - return readBits(type - MagnesiumValue.BITS_0); - } else if (type > MagnesiumValue.YIID_0) { - // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31' - return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0); - } else { - throw new InvalidNormalizedNodeStreamException("Invalid value type " + type); - } - } - } - - abstract @NonNull BigInteger readBigInteger() throws IOException; - - private byte @NonNull [] readBinary(final int size) throws IOException { - if (size > 0) { - final byte[] ret = new byte[size]; - input.readFully(ret); - return ret; - } else if (size == 0) { - return BINARY_0; - } else { - throw new InvalidNormalizedNodeStreamException("Invalid binary length " + size); - } - } - - private @NonNull ImmutableSet readBits(final int size) throws IOException { - if (size > 0) { - final ImmutableSet.Builder builder = ImmutableSet.builder(); - for (int i = 0; i < size; ++i) { - builder.add(readRefString()); - } - return builder.build(); - } else if (size == 0) { - return ImmutableSet.of(); - } else { - throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size); - } - } - - private static byte mask(final byte header, final byte mask) { - return (byte) (header & mask); - } - - private static int rshift(final byte header, final byte shift) { - return (header & 0xFF) >>> shift; - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java deleted file mode 100644 index f43a8c1eee..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2014, 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; - -/** - * Stream constants identifying individual node types. - */ -final class LithiumNode { - static final byte LEAF_NODE = 1; - static final byte LEAF_SET = 2; - static final byte LEAF_SET_ENTRY_NODE = 3; - static final byte CONTAINER_NODE = 4; - static final byte UNKEYED_LIST = 5; - static final byte UNKEYED_LIST_ITEM = 6; - static final byte MAP_NODE = 7; - static final byte MAP_ENTRY_NODE = 8; - static final byte ORDERED_MAP_NODE = 9; - static final byte CHOICE_NODE = 10; - static final byte AUGMENTATION_NODE = 11; - static final byte ANY_XML_NODE = 12; - static final byte END_NODE = 13; - static final byte ORDERED_LEAF_SET = 14; - // Note: never emitted as of yangtools-7.0.0 - @Deprecated - static final byte YANG_MODELED_ANY_XML_NODE = 15; - - private LithiumNode() { - // Utility class - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java deleted file mode 100755 index 8734b5db75..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2014, 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 com.google.common.base.Strings; -import java.io.DataInput; -import java.io.IOException; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; - -/** - * Lithium (or Oxygen really) specialization of AbstractLithiumDataInput. - */ -final class LithiumNormalizedNodeInputStreamReader extends AbstractLithiumDataInput { - LithiumNormalizedNodeInputStreamReader(final DataInput input) { - super(input); - } - - @Override - @Deprecated(since = "11.0.0", forRemoval = true) - public NormalizedNodeStreamVersion getVersion() { - return NormalizedNodeStreamVersion.LITHIUM; - } - - @Override - public QName readQName() throws IOException { - // Read in the same sequence of writing - String localName = readCodedString(); - String namespace = readCodedString(); - String revision = Strings.emptyToNull(readCodedString()); - - return QNameFactory.create(localName, namespace, revision); - } - - @Override - LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException { - return defaultReadAugmentationIdentifier(); - } - - @Override - NodeIdentifier readNodeIdentifier() throws IOException { - return new NodeIdentifier(readQName()); - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java deleted file mode 100644 index 63a2a1057a..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014 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 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; - -final class LithiumPathArgument { - static final byte AUGMENTATION_IDENTIFIER = 1; - static final byte NODE_IDENTIFIER = 2; - static final byte NODE_IDENTIFIER_WITH_VALUE = 3; - static final byte NODE_IDENTIFIER_WITH_PREDICATES = 4; - - private LithiumPathArgument() { - // Utility class - } - - static byte getSerializablePathArgumentType(final PathArgument pathArgument) { - if (pathArgument instanceof NodeIdentifier) { - return NODE_IDENTIFIER; - } else if (pathArgument instanceof NodeIdentifierWithPredicates) { - return NODE_IDENTIFIER_WITH_PREDICATES; - } else if (pathArgument instanceof NodeWithValue) { - return NODE_IDENTIFIER_WITH_VALUE; - } else { - throw new IllegalArgumentException("Unknown type of PathArgument = " + pathArgument); - } - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java deleted file mode 100644 index 25bcfbefab..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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; - -/** - * Tokens related to Lithium/NeonSR2 encoding. - */ -final class LithiumTokens { - /** - * The value is a reference to a previously-defined entity, typically through {@link #IS_STRING_VALUE}. - */ - static final byte IS_CODE_VALUE = 1; - /** - * The value is a String, which needs to be kept memoized for the purposes for being referenced by - * {@link #IS_CODE_VALUE}. - */ - static final byte IS_STRING_VALUE = 2; - /** - * The value is an explicit null. - */ - static final byte IS_NULL_VALUE = 3; - - private LithiumTokens() { - - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java deleted file mode 100644 index c717b47012..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014 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; - -final class LithiumValue { - // The String length threshold beyond which a String should be encoded as bytes - static final int STRING_BYTES_LENGTH_THRESHOLD = Short.MAX_VALUE / 4; - - static final byte SHORT_TYPE = 1; - static final byte BYTE_TYPE = 2; - static final byte INT_TYPE = 3; - static final byte LONG_TYPE = 4; - static final byte BOOL_TYPE = 5; - static final byte QNAME_TYPE = 6; - static final byte BITS_TYPE = 7; - static final byte YANG_IDENTIFIER_TYPE = 8; - static final byte STRING_TYPE = 9; - static final byte BIG_INTEGER_TYPE = 10; - static final byte BIG_DECIMAL_TYPE = 11; - static final byte BINARY_TYPE = 12; - // Leaf nodes no longer allow null values. The "empty" type is now represented as - // org.opendaylight.yangtools.yang.common.Empty. This is kept for backwards compatibility. - @Deprecated - static final byte NULL_TYPE = 13; - static final byte STRING_BYTES_TYPE = 14; - static final byte EMPTY_TYPE = 15; - - private LithiumValue() { - // Utility class - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/MagnesiumDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/MagnesiumDataInput.java index 08adc4630a..41f5a885a3 100644 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/MagnesiumDataInput.java +++ b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/MagnesiumDataInput.java @@ -7,11 +7,65 @@ */ package org.opendaylight.yangtools.yang.data.codec.binfmt; +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; +import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.UncheckedExecutionException; import java.io.DataInput; import java.io.IOException; -import java.math.BigInteger; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import javax.xml.transform.dom.DOMSource; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.concepts.Either; +import org.opendaylight.yangtools.util.xml.UntrustedXML; +import org.opendaylight.yangtools.yang.common.Decimal64; +import org.opendaylight.yangtools.yang.common.Empty; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.Uint16; +import org.opendaylight.yangtools.yang.common.Uint32; +import org.opendaylight.yangtools.yang.common.Uint64; +import org.opendaylight.yangtools.yang.common.Uint8; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * NormalizedNodeDataInput based on {@link MagnesiumNode}, {@link MagnesiumPathArgument} and {@link MagnesiumValue}. + */ +final class MagnesiumDataInput extends AbstractLegacyDataInput { + private static final Logger LOG = LoggerFactory.getLogger(MagnesiumDataInput.class); + + // Known singleton objects + private static final @NonNull Byte INT8_0 = 0; + private static final @NonNull Short INT16_0 = 0; + private static final @NonNull Integer INT32_0 = 0; + private static final @NonNull Long INT64_0 = 0L; + private static final byte @NonNull[] BINARY_0 = new byte[0]; + private static final @NonNull LegacyAugmentationIdentifier EMPTY_AID = + new LegacyAugmentationIdentifier(ImmutableSet.of()); + + private final List codedAugments = new ArrayList<>(); + private final List codedNodeIdentifiers = new ArrayList<>(); + private final List codedModules = new ArrayList<>(); + private final List codedStrings = new ArrayList<>(); -final class MagnesiumDataInput extends AbstractMagnesiumDataInput { MagnesiumDataInput(final DataInput input) { super(input); } @@ -22,7 +76,736 @@ final class MagnesiumDataInput extends AbstractMagnesiumDataInput { } @Override - BigInteger readBigInteger() throws IOException { - throw new InvalidNormalizedNodeStreamException("BigInteger coding is not supported"); + public void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException { + streamNormalizedNode(requireNonNull(writer), null, input.readByte()); + } + + private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final Object parent, + final byte nodeHeader) throws IOException { + switch (nodeHeader & MagnesiumNode.TYPE_MASK) { + case MagnesiumNode.NODE_LEAF: + streamLeaf(writer, parent, nodeHeader); + break; + case MagnesiumNode.NODE_CONTAINER: + streamContainer(writer, nodeHeader); + break; + case MagnesiumNode.NODE_LIST: + streamList(writer, nodeHeader); + break; + case MagnesiumNode.NODE_MAP: + streamMap(writer, nodeHeader); + break; + case MagnesiumNode.NODE_MAP_ORDERED: + streamMapOrdered(writer, nodeHeader); + break; + case MagnesiumNode.NODE_LEAFSET: + streamLeafset(writer, nodeHeader); + break; + case MagnesiumNode.NODE_LEAFSET_ORDERED: + streamLeafsetOrdered(writer, nodeHeader); + break; + case MagnesiumNode.NODE_CHOICE: + streamChoice(writer, nodeHeader); + break; + case MagnesiumNode.NODE_AUGMENTATION: + streamAugmentation(writer, nodeHeader); + break; + case MagnesiumNode.NODE_ANYXML: + streamAnyxml(writer, nodeHeader); + break; + case MagnesiumNode.NODE_LIST_ENTRY: + streamListEntry(writer, parent, nodeHeader); + break; + case MagnesiumNode.NODE_LEAFSET_ENTRY: + streamLeafsetEntry(writer, parent, nodeHeader); + break; + case MagnesiumNode.NODE_MAP_ENTRY: + streamMapEntry(writer, parent, nodeHeader); + break; + default: + throw new InvalidNormalizedNodeStreamException("Unexpected node header " + nodeHeader); + } + } + + private void streamAnyxml(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming anyxml node {}", identifier); + + final DOMSource value = readDOMSource(); + if (writer.startAnyxmlNode(identifier, DOMSource.class)) { + writer.domSourceValue(value); + writer.endNode(); + } + } + + private void streamAugmentation(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final var augIdentifier = decodeAugmentationIdentifier(nodeHeader); + LOG.trace("Streaming augmentation node {}", augIdentifier); + for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) { + streamNormalizedNode(writer, augIdentifier, nodeType); + } + } + + private void streamChoice(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming choice node {}", identifier); + writer.startChoiceNode(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamContainer(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming container node {}", identifier); + writer.startContainerNode(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamLeaf(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) + throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming leaf node {}", identifier); + writer.startLeafNode(identifier); + + final Object value; + if ((nodeHeader & MagnesiumNode.PREDICATE_ONE) == MagnesiumNode.PREDICATE_ONE) { + if (!(parent instanceof NodeIdentifierWithPredicates nip)) { + throw new InvalidNormalizedNodeStreamException("Invalid predicate leaf " + identifier + " in parent " + + parent); + } + + value = nip.getValue(identifier.getNodeType()); + if (value == null) { + throw new InvalidNormalizedNodeStreamException("Failed to find predicate leaf " + identifier + + " in parent " + parent); + } + } else { + value = readLeafValue(); + } + + writer.scalarValue(value); + writer.endNode(); + } + + private void streamLeafset(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming leaf set node {}", identifier); + writer.startLeafSet(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamLeafsetOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) + throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming ordered leaf set node {}", identifier); + writer.startOrderedLeafSet(identifier, UNKNOWN_SIZE); + + commonStreamContainer(writer, identifier); + } + + private void streamLeafsetEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) + throws IOException { + final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent); + final Object value = readLeafValue(); + final NodeWithValue leafIdentifier = new NodeWithValue<>(nodeId.getNodeType(), value); + LOG.trace("Streaming leaf set entry node {}", leafIdentifier); + writer.startLeafSetEntryNode(leafIdentifier); + writer.scalarValue(value); + writer.endNode(); + } + + private void streamList(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + writer.startUnkeyedList(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamListEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) + throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader, parent); + LOG.trace("Streaming unkeyed list item node {}", identifier); + writer.startUnkeyedListItem(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamMap(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming map node {}", identifier); + writer.startMapNode(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamMapOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException { + final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader); + LOG.trace("Streaming ordered map node {}", identifier); + writer.startOrderedMapNode(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void streamMapEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader) + throws IOException { + final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent); + + final int size = switch (mask(nodeHeader, MagnesiumNode.PREDICATE_MASK)) { + case MagnesiumNode.PREDICATE_ZERO -> 0; + case MagnesiumNode.PREDICATE_ONE -> 1; + case MagnesiumNode.PREDICATE_1B -> input.readUnsignedByte(); + case MagnesiumNode.PREDICATE_4B -> input.readInt(); + default -> + // ISE on purpose: this should never ever happen + throw new IllegalStateException("Failed to decode NodeIdentifierWithPredicates size from header " + + nodeHeader); + }; + final NodeIdentifierWithPredicates identifier = readNodeIdentifierWithPredicates(nodeId.getNodeType(), size); + LOG.trace("Streaming map entry node {}", identifier); + writer.startMapEntryNode(identifier, UNKNOWN_SIZE); + commonStreamContainer(writer, identifier); + } + + private void commonStreamContainer(final NormalizedNodeStreamWriter writer, final PathArgument parent) + throws IOException { + for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) { + streamNormalizedNode(writer, parent, nodeType); + } + writer.endNode(); + } + + private @NonNull NodeIdentifier decodeNodeIdentifier() throws IOException { + final QNameModule module = decodeQNameModule(); + final String localName = readRefString(); + final NodeIdentifier nodeId; + try { + nodeId = QNameFactory.getNodeIdentifier(module, localName); + } catch (ExecutionException e) { + throw new InvalidNormalizedNodeStreamException("Illegal QName module=" + module + " localName=" + + localName, e); + } + + codedNodeIdentifiers.add(nodeId); + return nodeId; + } + + private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader) throws IOException { + return decodeNodeIdentifier(nodeHeader, null); + } + + private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader, final Object parent) throws IOException { + final int index; + switch (nodeHeader & MagnesiumNode.ADDR_MASK) { + case MagnesiumNode.ADDR_DEFINE: + return readNodeIdentifier(); + case MagnesiumNode.ADDR_LOOKUP_1B: + index = input.readUnsignedByte(); + break; + case MagnesiumNode.ADDR_LOOKUP_4B: + index = input.readInt(); + break; + case MagnesiumNode.ADDR_PARENT: + if (parent instanceof NodeIdentifier nid) { + return nid; + } + throw new InvalidNormalizedNodeStreamException("Invalid node identifier reference to parent " + parent); + default: + throw new InvalidNormalizedNodeStreamException("Unexpected node identifier addressing in header " + + nodeHeader); + } + + try { + return codedNodeIdentifiers.get(index); + } catch (IndexOutOfBoundsException e) { + throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e); + } + } + + private LegacyAugmentationIdentifier decodeAugmentationIdentifier(final byte nodeHeader) throws IOException { + final int index; + switch (nodeHeader & MagnesiumNode.ADDR_MASK) { + case MagnesiumNode.ADDR_DEFINE: + return readAugmentationIdentifier(); + case MagnesiumNode.ADDR_LOOKUP_1B: + index = input.readUnsignedByte(); + break; + case MagnesiumNode.ADDR_LOOKUP_4B: + index = input.readInt(); + break; + default: + throw new InvalidNormalizedNodeStreamException( + "Unexpected augmentation identifier addressing in header " + nodeHeader); + } + + try { + return codedAugments.get(index); + } catch (IndexOutOfBoundsException e) { + throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier reference " + index, e); + } + } + + @Override + public YangInstanceIdentifier readYangInstanceIdentifier() throws IOException { + final byte type = input.readByte(); + if (type == MagnesiumValue.YIID) { + return readYangInstanceIdentifier(input.readInt()); + } else if (type >= MagnesiumValue.YIID_0) { + // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31' + return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0); + } else { + throw new InvalidNormalizedNodeStreamException("Unexpected YangInstanceIdentifier type " + type); + } + } + + private @NonNull YangInstanceIdentifier readYangInstanceIdentifier(final int size) throws IOException { + if (size > 0) { + final Builder builder = ImmutableList.builderWithExpectedSize(size); + for (int i = 0; i < size; ++i) { + builder.add(readPathArgument()); + } + return YangInstanceIdentifier.of(builder.build()); + } else if (size == 0) { + return YangInstanceIdentifier.of(); + } else { + throw new InvalidNormalizedNodeStreamException("Invalid YangInstanceIdentifier size " + size); + } + } + + @Override + public QName readQName() throws IOException { + final byte type = input.readByte(); + return switch (type) { + case MagnesiumValue.QNAME -> decodeQName(); + case MagnesiumValue.QNAME_REF_1B -> decodeQNameRef1(); + case MagnesiumValue.QNAME_REF_2B -> decodeQNameRef2(); + case MagnesiumValue.QNAME_REF_4B -> decodeQNameRef4(); + default -> throw new InvalidNormalizedNodeStreamException("Unexpected QName type " + type); + }; + } + + @Override + @Deprecated(since = "11.0.0", forRemoval = true) + public Either readLegacyPathArgument() throws IOException { + final byte header = input.readByte(); + return switch (header & MagnesiumPathArgument.TYPE_MASK) { + case MagnesiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier(header)); + case MagnesiumPathArgument.NODE_IDENTIFIER -> { + verifyPathIdentifierOnly(header); + yield Either.ofFirst(readNodeIdentifier(header)); + } + case MagnesiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES -> + Either.ofFirst(readNodeIdentifierWithPredicates(header)); + case MagnesiumPathArgument.NODE_WITH_VALUE -> { + verifyPathIdentifierOnly(header); + yield Either.ofFirst(readNodeWithValue(header)); + } + case MagnesiumPathArgument.MOUNTPOINT_IDENTIFIER -> { + verifyPathIdentifierOnly(header); + yield Either.ofSecond(new LegacyMountPointIdentifier(readNodeIdentifier(header).getNodeType())); + } + default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument header " + header); + }; + } + + private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException { + final var result = readAugmentationIdentifier(input.readInt()); + codedAugments.add(result); + return result; + } + + private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final byte header) throws IOException { + final byte count = mask(header, MagnesiumPathArgument.AID_COUNT_MASK); + return switch (count) { + case MagnesiumPathArgument.AID_COUNT_1B -> readAugmentationIdentifier(input.readUnsignedByte()); + case MagnesiumPathArgument.AID_COUNT_2B -> readAugmentationIdentifier(input.readUnsignedShort()); + case MagnesiumPathArgument.AID_COUNT_4B -> readAugmentationIdentifier(input.readInt()); + default -> readAugmentationIdentifier(rshift(count, MagnesiumPathArgument.AID_COUNT_SHIFT)); + }; + } + + private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final int size) throws IOException { + if (size > 0) { + final var qnames = ImmutableSet.builderWithExpectedSize(size); + for (int i = 0; i < size; ++i) { + qnames.add(readQName()); + } + return new LegacyAugmentationIdentifier(qnames.build()); + } else if (size == 0) { + return EMPTY_AID; + } else { + throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier size " + size); + } + } + + private @NonNull NodeIdentifier readNodeIdentifier() throws IOException { + return decodeNodeIdentifier(); + } + + private @NonNull NodeIdentifier readNodeIdentifier(final byte header) throws IOException { + return switch (header & MagnesiumPathArgument.QNAME_MASK) { + case MagnesiumPathArgument.QNAME_DEF -> decodeNodeIdentifier(); + case MagnesiumPathArgument.QNAME_REF_1B -> decodeNodeIdentifierRef1(); + case MagnesiumPathArgument.QNAME_REF_2B -> decodeNodeIdentifierRef2(); + case MagnesiumPathArgument.QNAME_REF_4B -> decodeNodeIdentifierRef4(); + default -> throw new InvalidNormalizedNodeStreamException("Invalid QName coding in " + header); + }; + } + + private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header) + throws IOException { + final QName qname = readNodeIdentifier(header).getNodeType(); + return switch (mask(header, MagnesiumPathArgument.SIZE_MASK)) { + case MagnesiumPathArgument.SIZE_1B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedByte()); + case MagnesiumPathArgument.SIZE_2B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedShort()); + case MagnesiumPathArgument.SIZE_4B -> readNodeIdentifierWithPredicates(qname, input.readInt()); + default -> readNodeIdentifierWithPredicates(qname, rshift(header, MagnesiumPathArgument.SIZE_SHIFT)); + }; + } + + private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final QName qname, final int size) + throws IOException { + if (size == 1) { + return NodeIdentifierWithPredicates.of(qname, readQName(), readLeafValue()); + } else if (size > 1) { + final ImmutableMap.Builder builder = ImmutableMap.builderWithExpectedSize(size); + for (int i = 0; i < size; ++i) { + builder.put(readQName(), readLeafValue()); + } + return NodeIdentifierWithPredicates.of(qname, builder.build()); + } else if (size == 0) { + return NodeIdentifierWithPredicates.of(qname); + } else { + throw new InvalidNormalizedNodeStreamException("Invalid predicate count " + size); + } + } + + private @NonNull NodeWithValue readNodeWithValue(final byte header) throws IOException { + final QName qname = readNodeIdentifier(header).getNodeType(); + return new NodeWithValue<>(qname, readLeafValue()); + } + + private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException { + if (mask(header, MagnesiumPathArgument.SIZE_MASK) != 0) { + throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header); + } + } + + private @NonNull NodeIdentifier decodeNodeIdentifierRef1() throws IOException { + return lookupNodeIdentifier(input.readUnsignedByte()); + } + + private @NonNull NodeIdentifier decodeNodeIdentifierRef2() throws IOException { + return lookupNodeIdentifier(input.readUnsignedShort() + 256); + } + + private @NonNull NodeIdentifier decodeNodeIdentifierRef4() throws IOException { + return lookupNodeIdentifier(input.readInt()); + } + + private @NonNull QName decodeQName() throws IOException { + return decodeNodeIdentifier().getNodeType(); + } + + private @NonNull QName decodeQNameRef1() throws IOException { + return lookupQName(input.readUnsignedByte()); + } + + private @NonNull QName decodeQNameRef2() throws IOException { + return lookupQName(input.readUnsignedShort() + 256); + } + + private @NonNull QName decodeQNameRef4() throws IOException { + return lookupQName(input.readInt()); + } + + private @NonNull QNameModule decodeQNameModule() throws IOException { + final byte type = input.readByte(); + final int index; + switch (type) { + case MagnesiumValue.MODREF_1B: + index = input.readUnsignedByte(); + break; + case MagnesiumValue.MODREF_2B: + index = input.readUnsignedShort() + 256; + break; + case MagnesiumValue.MODREF_4B: + index = input.readInt(); + break; + default: + return decodeQNameModuleDef(type); + } + + try { + return codedModules.get(index); + } catch (IndexOutOfBoundsException e) { + throw new InvalidNormalizedNodeStreamException("Invalid QNameModule reference " + index, e); + } + } + + // QNameModule definition, i.e. two encoded strings + private @NonNull QNameModule decodeQNameModuleDef(final byte type) throws IOException { + final String namespace = readRefString(type); + + final byte refType = input.readByte(); + final String revision = refType == MagnesiumValue.STRING_EMPTY ? null : readRefString(refType); + final QNameModule module; + try { + module = QNameFactory.createModule(namespace, revision); + } catch (UncheckedExecutionException e) { + throw new InvalidNormalizedNodeStreamException("Illegal QNameModule ns=" + namespace + " rev=" + revision, + e); + } + + codedModules.add(module); + return module; + } + + private @NonNull String readRefString() throws IOException { + return readRefString(input.readByte()); + } + + private @NonNull String readRefString(final byte type) throws IOException { + final String str; + switch (type) { + case MagnesiumValue.STRING_REF_1B: + return lookupString(input.readUnsignedByte()); + case MagnesiumValue.STRING_REF_2B: + return lookupString(input.readUnsignedShort() + 256); + case MagnesiumValue.STRING_REF_4B: + return lookupString(input.readInt()); + case MagnesiumValue.STRING_EMPTY: + return ""; + case MagnesiumValue.STRING_2B: + str = readString2(); + break; + case MagnesiumValue.STRING_4B: + str = readString4(); + break; + case MagnesiumValue.STRING_CHARS: + str = readCharsString(); + break; + case MagnesiumValue.STRING_UTF: + str = input.readUTF(); + break; + default: + throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type); + } + + // TODO: consider interning Strings -- that would help with bits, but otherwise it's probably not worth it + codedStrings.add(verifyNotNull(str)); + return str; + } + + private @NonNull String readString() throws IOException { + final byte type = input.readByte(); + return switch (type) { + case MagnesiumValue.STRING_EMPTY -> ""; + case MagnesiumValue.STRING_UTF -> input.readUTF(); + case MagnesiumValue.STRING_2B -> readString2(); + case MagnesiumValue.STRING_4B -> readString4(); + case MagnesiumValue.STRING_CHARS -> readCharsString(); + default -> throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type); + }; + } + + private @NonNull String readString2() throws IOException { + return readByteString(input.readUnsignedShort()); + } + + private @NonNull String readString4() throws IOException { + return readByteString(input.readInt()); + } + + private @NonNull String readByteString(final int size) throws IOException { + if (size > 0) { + final byte[] bytes = new byte[size]; + input.readFully(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } else if (size == 0) { + return ""; + } else { + throw new InvalidNormalizedNodeStreamException("Invalid String bytes length " + size); + } + } + + private @NonNull String readCharsString() throws IOException { + final int size = input.readInt(); + if (size > 0) { + final char[] chars = new char[size]; + for (int i = 0; i < size; ++i) { + chars[i] = input.readChar(); + } + return String.valueOf(chars); + } else if (size == 0) { + return ""; + } else { + throw new InvalidNormalizedNodeStreamException("Invalid String chars length " + size); + } + } + + private @NonNull NodeIdentifier lookupNodeIdentifier(final int index) throws InvalidNormalizedNodeStreamException { + try { + return codedNodeIdentifiers.get(index); + } catch (IndexOutOfBoundsException e) { + throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e); + } + } + + private @NonNull QName lookupQName(final int index) throws InvalidNormalizedNodeStreamException { + return lookupNodeIdentifier(index).getNodeType(); + } + + private @NonNull String lookupString(final int index) throws InvalidNormalizedNodeStreamException { + try { + return codedStrings.get(index); + } catch (IndexOutOfBoundsException e) { + throw new InvalidNormalizedNodeStreamException("Invalid String reference " + index, e); + } + } + + private @NonNull DOMSource readDOMSource() throws IOException { + final String str = readString(); + try { + return new DOMSource(UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(str))) + .getDocumentElement()); + } catch (SAXException e) { + throw new IOException("Error parsing XML: " + str, e); + } + } + + private @NonNull Object readLeafValue() throws IOException { + final byte type = input.readByte(); + switch (type) { + case MagnesiumValue.BOOLEAN_FALSE: + return Boolean.FALSE; + case MagnesiumValue.BOOLEAN_TRUE: + return Boolean.TRUE; + case MagnesiumValue.EMPTY: + return Empty.value(); + case MagnesiumValue.INT8: + return input.readByte(); + case MagnesiumValue.INT8_0: + return INT8_0; + case MagnesiumValue.INT16: + return input.readShort(); + case MagnesiumValue.INT16_0: + return INT16_0; + case MagnesiumValue.INT32: + return input.readInt(); + case MagnesiumValue.INT32_0: + return INT32_0; + case MagnesiumValue.INT32_2B: + return input.readShort() & 0xFFFF; + case MagnesiumValue.INT64: + return input.readLong(); + case MagnesiumValue.INT64_0: + return INT64_0; + case MagnesiumValue.INT64_4B: + return input.readInt() & 0xFFFFFFFFL; + case MagnesiumValue.UINT8: + return Uint8.fromByteBits(input.readByte()); + case MagnesiumValue.UINT8_0: + return Uint8.ZERO; + case MagnesiumValue.UINT16: + return Uint16.fromShortBits(input.readShort()); + case MagnesiumValue.UINT16_0: + return Uint16.ZERO; + case MagnesiumValue.UINT32: + return Uint32.fromIntBits(input.readInt()); + case MagnesiumValue.UINT32_0: + return Uint32.ZERO; + case MagnesiumValue.UINT32_2B: + return Uint32.fromIntBits(input.readShort() & 0xFFFF); + case MagnesiumValue.UINT64: + return Uint64.fromLongBits(input.readLong()); + case MagnesiumValue.UINT64_0: + return Uint64.ZERO; + case MagnesiumValue.UINT64_4B: + return Uint64.fromLongBits(input.readInt() & 0xFFFFFFFFL); + case MagnesiumValue.BIGDECIMAL: + // FIXME: use string -> BigDecimal cache + return Decimal64.valueOf(input.readUTF()); + case MagnesiumValue.BIGINTEGER: + throw new InvalidNormalizedNodeStreamException("BigInteger coding is not supported"); + case MagnesiumValue.STRING_EMPTY: + return ""; + case MagnesiumValue.STRING_UTF: + return input.readUTF(); + case MagnesiumValue.STRING_2B: + return readString2(); + case MagnesiumValue.STRING_4B: + return readString4(); + case MagnesiumValue.STRING_CHARS: + return readCharsString(); + case MagnesiumValue.BINARY_0: + return BINARY_0; + case MagnesiumValue.BINARY_1B: + return readBinary(128 + input.readUnsignedByte()); + case MagnesiumValue.BINARY_2B: + return readBinary(384 + input.readUnsignedShort()); + case MagnesiumValue.BINARY_4B: + return readBinary(input.readInt()); + case MagnesiumValue.YIID_0: + return YangInstanceIdentifier.of(); + case MagnesiumValue.YIID: + return readYangInstanceIdentifier(input.readInt()); + case MagnesiumValue.QNAME: + return decodeQName(); + case MagnesiumValue.QNAME_REF_1B: + return decodeQNameRef1(); + case MagnesiumValue.QNAME_REF_2B: + return decodeQNameRef2(); + case MagnesiumValue.QNAME_REF_4B: + return decodeQNameRef4(); + case MagnesiumValue.BITS_0: + return ImmutableSet.of(); + case MagnesiumValue.BITS_1B: + return readBits(input.readUnsignedByte() + 29); + case MagnesiumValue.BITS_2B: + return readBits(input.readUnsignedShort() + 285); + case MagnesiumValue.BITS_4B: + return readBits(input.readInt()); + + default: + if (type > MagnesiumValue.BINARY_0 && type <= MagnesiumValue.BINARY_127) { + return readBinary(type - MagnesiumValue.BINARY_0); + } else if (type > MagnesiumValue.BITS_0 && type < MagnesiumValue.BITS_1B) { + return readBits(type - MagnesiumValue.BITS_0); + } else if (type > MagnesiumValue.YIID_0) { + // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31' + return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0); + } else { + throw new InvalidNormalizedNodeStreamException("Invalid value type " + type); + } + } + } + + private byte @NonNull [] readBinary(final int size) throws IOException { + if (size > 0) { + final byte[] ret = new byte[size]; + input.readFully(ret); + return ret; + } else if (size == 0) { + return BINARY_0; + } else { + throw new InvalidNormalizedNodeStreamException("Invalid binary length " + size); + } + } + + private @NonNull ImmutableSet readBits(final int size) throws IOException { + if (size > 0) { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (int i = 0; i < size; ++i) { + builder.add(readRefString()); + } + return builder.build(); + } else if (size == 0) { + return ImmutableSet.of(); + } else { + throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size); + } + } + + private static byte mask(final byte header, final byte mask) { + return (byte) (header & mask); + } + + private static int rshift(final byte header, final byte shift) { + return (header & 0xFF) >>> shift; } } diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java deleted file mode 100644 index 1eb8412f21..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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 com.google.common.base.Verify.verify; - -import java.io.DataInput; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; - -/** - * Neon SR2 specialization of AbstractLithiumDataInput. Unlike its Lithium counterpart, this format uses coding for - * QNameModules, QNames, NodeIdentifiers and AugmentationIdentifiers, thus reducing stream duplication. - */ -final class NeonSR2NormalizedNodeInputStreamReader extends AbstractLithiumDataInput { - private final ArrayList codedNodeIdentifiers = new ArrayList<>(); - private final List codedAugments = new ArrayList<>(); - private final List codedModules = new ArrayList<>(); - private final List codedQNames = new ArrayList<>(); - - NeonSR2NormalizedNodeInputStreamReader(final DataInput input) { - super(input); - } - - @Override - @Deprecated(since = "11.0.0", forRemoval = true) - public NormalizedNodeStreamVersion getVersion() { - return NormalizedNodeStreamVersion.NEON_SR2; - } - - @Override - public QName readQName() throws IOException { - final byte valueType = readByte(); - return switch (valueType) { - case NeonSR2Tokens.IS_QNAME_CODE -> codedQName(readInt()); - case NeonSR2Tokens.IS_QNAME_VALUE -> rawQName(); - default -> throw new IOException("Unhandled QName value type " + valueType); - }; - } - - @Override - LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException { - final byte valueType = readByte(); - return switch (valueType) { - case NeonSR2Tokens.IS_AUGMENT_CODE -> codedAugmentId(readInt()); - case NeonSR2Tokens.IS_AUGMENT_VALUE -> rawAugmentId(); - default -> throw new IOException("Unhandled AugmentationIdentifier value type " + valueType); - }; - } - - @Override - NodeIdentifier readNodeIdentifier() throws IOException { - // NodeIdentifier rides on top of QName, with this method really saying 'interpret next QName as NodeIdentifier' - // to do that we inter-mingle with readQName() - final byte valueType = readByte(); - return switch (valueType) { - case NeonSR2Tokens.IS_QNAME_CODE -> codedNodeIdentifier(readInt()); - case NeonSR2Tokens.IS_QNAME_VALUE -> rawNodeIdentifier(); - default -> throw new IOException("Unhandled NodeIdentifier value type " + valueType); - }; - } - - private QNameModule readModule() throws IOException { - final byte valueType = readByte(); - return switch (valueType) { - case NeonSR2Tokens.IS_MODULE_CODE -> codedModule(readInt()); - case NeonSR2Tokens.IS_MODULE_VALUE -> rawModule(); - default -> throw new IOException("Unhandled QNameModule value type " + valueType); - }; - } - - private NodeIdentifier codedNodeIdentifier(final int code) throws IOException { - final NodeIdentifier existing = codedNodeIdentifiers.size() > code ? codedNodeIdentifiers.get(code) : null; - return existing != null ? existing : storeNodeIdentifier(code, codedQName(code)); - } - - private NodeIdentifier rawNodeIdentifier() throws IOException { - // Capture size before it incremented - final int code = codedQNames.size(); - return storeNodeIdentifier(code, rawQName()); - } - - private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) { - final NodeIdentifier ret = NodeIdentifier.create(qname); - final int size = codedNodeIdentifiers.size(); - - if (code >= size) { - // Null-fill others - codedNodeIdentifiers.ensureCapacity(code + 1); - for (int i = size; i < code; ++i) { - codedNodeIdentifiers.add(null); - } - - codedNodeIdentifiers.add(ret); - } else { - final NodeIdentifier check = codedNodeIdentifiers.set(code, ret); - verify(check == null); - } - - return ret; - } - - private QName codedQName(final int code) throws IOException { - return getCode("QName", codedQNames, code); - } - - private QName rawQName() throws IOException { - final String localName = readCodedString(); - final QNameModule module = readModule(); - final QName qname = QNameFactory.create(module, localName); - codedQNames.add(qname); - return qname; - } - - private LegacyAugmentationIdentifier codedAugmentId(final int code) throws IOException { - return getCode("QName set", codedAugments, code); - } - - private LegacyAugmentationIdentifier rawAugmentId() throws IOException { - final var aid = defaultReadAugmentationIdentifier(); - codedAugments.add(aid); - return aid; - } - - private QNameModule codedModule(final int code) throws IOException { - return getCode("Module", codedModules, code); - } - - private QNameModule rawModule() throws IOException { - final String namespace = readCodedString(); - final String revision = readCodedString(); - final QNameModule mod = QNameFactory.createModule(namespace, revision); - codedModules.add(mod); - return mod; - } - - private static T getCode(final String name, final List list, final int code) throws IOException { - try { - return list.get(code); - } catch (IndexOutOfBoundsException e) { - throw new IOException(name + " code " + code + " was not found", e); - } - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java deleted file mode 100644 index a75f1a511e..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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; - -/** - * Tokens used in Neon SR2 encoding. Note that Neon SR2 builds on top of Lithium, hence the token values must never - * overlap. - */ -final class NeonSR2Tokens { - static final byte IS_QNAME_CODE = 4; - static final byte IS_QNAME_VALUE = 5; - static final byte IS_AUGMENT_CODE = 6; - static final byte IS_AUGMENT_VALUE = 7; - static final byte IS_MODULE_CODE = 8; - static final byte IS_MODULE_VALUE = 9; - - private NeonSR2Tokens() { - - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NormalizedNodeStreamVersion.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NormalizedNodeStreamVersion.java index 48f4defd4e..16b62a9a67 100644 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NormalizedNodeStreamVersion.java +++ b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NormalizedNodeStreamVersion.java @@ -18,69 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.ValueNode; */ @NonNullByDefault public enum NormalizedNodeStreamVersion { - /** - * Original stream version, as shipped in OpenDaylight Lithium simultaneous release. The caveat here is that this - * version has augmented in OpenDaylight Oxygen to retrofit a non-null representation of the empty type. - * - * @deprecated This version cannot be written in and always required adaption. This version should not be relied - * upon, as it is subject to removal in a future version. - */ - @Deprecated(since = "11.0.0", forRemoval = true) - LITHIUM { - /** - * {@inheritDoc} - * @implSpec - * This method always throws {@link UnsupportedOperationException}. - * @deprecated This version is a historic one and writeout is not supported - */ - @Override - @Deprecated(since = "10.0.0", forRemoval = true) - public NormalizedNodeDataOutput newDataOutput(final DataOutput output) { - throw new UnsupportedOperationException(); - } - }, - /** - * Updated stream version, as shipped in OpenDaylight Neon SR2 release. Improves identifier encoding over - * {@link #LITHIUM}, so that QName caching is more effective. - * - * @deprecated This version cannot be written in and always required adaption. This version should not be relied - * upon, as it is subject to removal in a future version. - */ - @Deprecated(since = "11.0.0", forRemoval = true) - NEON_SR2 { - /** - * {@inheritDoc} - * @implSpec - * This method always throws {@link UnsupportedOperationException}. - * @deprecated This version is a historic one and writeout is not supported - */ - @Override - @Deprecated(since = "10.0.0", forRemoval = true) - public NormalizedNodeDataOutput newDataOutput(final DataOutput output) { - throw new UnsupportedOperationException(); - } - }, - /** - * First shipping in Sodium SR1. Improved stream coding to eliminate redundancies present in {@link #NEON_SR2}. - * Supports {@code Uint8} et al. as well as {@link BigInteger}. - * - * @deprecated This version cannot be written in and always required adaption. This version should not be relied - * upon, as it is subject to removal in a future version. - */ - @Deprecated(since = "11.0.0", forRemoval = true) - SODIUM_SR1 { - /** - * {@inheritDoc} - * @implSpec - * This method always throws {@link UnsupportedOperationException}. - * @deprecated This version is a historic one and writeout is not supported - */ - @Override - @Deprecated(since = "10.0.0", forRemoval = true) - public NormalizedNodeDataOutput newDataOutput(final DataOutput output) { - throw new UnsupportedOperationException(); - } - }, /** * First shipping is Magnesium. Does not support {@link BigInteger} mirroring it being superseded by {@link Uint64} * in {@link ValueNode#body()}. diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java deleted file mode 100644 index aa748d2164..0000000000 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.io.DataInput; -import java.io.IOException; -import java.math.BigInteger; - -final class SodiumSR1DataInput extends AbstractMagnesiumDataInput { - SodiumSR1DataInput(final DataInput input) { - super(input); - } - - @Override - @Deprecated(since = "11.0.0", forRemoval = true) - public NormalizedNodeStreamVersion getVersion() { - return NormalizedNodeStreamVersion.SODIUM_SR1; - } - - @Override - BigInteger readBigInteger() throws IOException { - // FIXME: use string -> BigInteger cache - return new BigInteger(input.readUTF()); - } -} diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/TokenTypes.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/TokenTypes.java index 7dbb80d501..765c31b61f 100644 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/TokenTypes.java +++ b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/TokenTypes.java @@ -10,19 +10,16 @@ package org.opendaylight.yangtools.yang.data.codec.binfmt; final class TokenTypes { static final byte SIGNATURE_MARKER = (byte) 0xab; - /** - * Original stream version. Uses a per-stream dictionary for strings. QNames are serialized as three strings. - */ - static final short LITHIUM_VERSION = 1; - /** - * Revised stream version. Unlike {@link #LITHIUM_VERSION}, QNames and QNameModules are using a per-stream - * dictionary, too. - */ - static final short NEON_SR2_VERSION = 2; - /** - * From-scratch designed version shipping in Sodium SR1. - */ - static final short SODIUM_SR1_VERSION = 3; + // Original stream version. Uses a per-stream dictionary for strings. QNames are serialized as three strings. + // LITHIUM_VERSION = 1; + // + // Revised stream version. Unlike {@link #LITHIUM_VERSION}, QNames and QNameModules are using a per-stream + // dictionary, too. + // NEON_SR2_VERSION = 2; + // + // From-scratch designed version shipping in Sodium SR1. + // SODIUM_SR1_VERSION = 3; + /** * Magnesium version. Structurally matches {@link #SODIUM_SR1_VERSION}, but does not allow BigIntegers to be * present. diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/VersionedNormalizedNodeDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/VersionedNormalizedNodeDataInput.java index c2632e9885..5e25856d64 100644 --- a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/VersionedNormalizedNodeDataInput.java +++ b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/VersionedNormalizedNodeDataInput.java @@ -33,9 +33,6 @@ final class VersionedNormalizedNodeDataInput extends ForwardingNormalizedNodeDat final short version = input.readShort(); final NormalizedNodeDataInput ret = switch (version) { - case TokenTypes.LITHIUM_VERSION -> new LithiumNormalizedNodeInputStreamReader(input); - case TokenTypes.NEON_SR2_VERSION -> new NeonSR2NormalizedNodeInputStreamReader(input); - case TokenTypes.SODIUM_SR1_VERSION -> new SodiumSR1DataInput(input); case TokenTypes.MAGNESIUM_VERSION -> new MagnesiumDataInput(input); case TokenTypes.POTASSIUM_VERSION -> new PotassiumDataInput(input); default -> throw defunct("Unhandled stream version %s", version); -- 2.36.6