2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.codec.binfmt;
10 import static com.google.common.base.Verify.verify;
12 import java.io.DataInput;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.common.QNameModule;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 * Neon SR2 specialization of AbstractLithiumDataInput. Unlike its Lithium counterpart, this format uses coding for
22 * QNameModules, QNames, NodeIdentifiers and AugmentationIdentifiers, thus reducing stream duplication.
24 final class NeonSR2NormalizedNodeInputStreamReader extends AbstractLithiumDataInput {
25 private final ArrayList<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
26 private final List<LegacyAugmentationIdentifier> codedAugments = new ArrayList<>();
27 private final List<QNameModule> codedModules = new ArrayList<>();
28 private final List<QName> codedQNames = new ArrayList<>();
30 NeonSR2NormalizedNodeInputStreamReader(final DataInput input) {
35 @Deprecated(since = "11.0.0", forRemoval = true)
36 public NormalizedNodeStreamVersion getVersion() {
37 return NormalizedNodeStreamVersion.NEON_SR2;
41 public QName readQName() throws IOException {
42 final byte valueType = readByte();
43 return switch (valueType) {
44 case NeonSR2Tokens.IS_QNAME_CODE -> codedQName(readInt());
45 case NeonSR2Tokens.IS_QNAME_VALUE -> rawQName();
46 default -> throw new IOException("Unhandled QName value type " + valueType);
51 LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException {
52 final byte valueType = readByte();
53 return switch (valueType) {
54 case NeonSR2Tokens.IS_AUGMENT_CODE -> codedAugmentId(readInt());
55 case NeonSR2Tokens.IS_AUGMENT_VALUE -> rawAugmentId();
56 default -> throw new IOException("Unhandled AugmentationIdentifier value type " + valueType);
61 NodeIdentifier readNodeIdentifier() throws IOException {
62 // NodeIdentifier rides on top of QName, with this method really saying 'interpret next QName as NodeIdentifier'
63 // to do that we inter-mingle with readQName()
64 final byte valueType = readByte();
65 return switch (valueType) {
66 case NeonSR2Tokens.IS_QNAME_CODE -> codedNodeIdentifier(readInt());
67 case NeonSR2Tokens.IS_QNAME_VALUE -> rawNodeIdentifier();
68 default -> throw new IOException("Unhandled NodeIdentifier value type " + valueType);
72 private QNameModule readModule() throws IOException {
73 final byte valueType = readByte();
74 return switch (valueType) {
75 case NeonSR2Tokens.IS_MODULE_CODE -> codedModule(readInt());
76 case NeonSR2Tokens.IS_MODULE_VALUE -> rawModule();
77 default -> throw new IOException("Unhandled QNameModule value type " + valueType);
81 private NodeIdentifier codedNodeIdentifier(final int code) throws IOException {
82 final NodeIdentifier existing = codedNodeIdentifiers.size() > code ? codedNodeIdentifiers.get(code) : null;
83 return existing != null ? existing : storeNodeIdentifier(code, codedQName(code));
86 private NodeIdentifier rawNodeIdentifier() throws IOException {
87 // Capture size before it incremented
88 final int code = codedQNames.size();
89 return storeNodeIdentifier(code, rawQName());
92 private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) {
93 final NodeIdentifier ret = NodeIdentifier.create(qname);
94 final int size = codedNodeIdentifiers.size();
98 codedNodeIdentifiers.ensureCapacity(code + 1);
99 for (int i = size; i < code; ++i) {
100 codedNodeIdentifiers.add(null);
103 codedNodeIdentifiers.add(ret);
105 final NodeIdentifier check = codedNodeIdentifiers.set(code, ret);
106 verify(check == null);
112 private QName codedQName(final int code) throws IOException {
113 return getCode("QName", codedQNames, code);
116 private QName rawQName() throws IOException {
117 final String localName = readCodedString();
118 final QNameModule module = readModule();
119 final QName qname = QNameFactory.create(module, localName);
120 codedQNames.add(qname);
124 private LegacyAugmentationIdentifier codedAugmentId(final int code) throws IOException {
125 return getCode("QName set", codedAugments, code);
128 private LegacyAugmentationIdentifier rawAugmentId() throws IOException {
129 final var aid = defaultReadAugmentationIdentifier();
130 codedAugments.add(aid);
134 private QNameModule codedModule(final int code) throws IOException {
135 return getCode("Module", codedModules, code);
138 private QNameModule rawModule() throws IOException {
139 final String namespace = readCodedString();
140 final String revision = readCodedString();
141 final QNameModule mod = QNameFactory.createModule(namespace, revision);
142 codedModules.add(mod);
146 private static <T> T getCode(final String name, final List<T> list, final int code) throws IOException {
148 return list.get(code);
149 } catch (IndexOutOfBoundsException e) {
150 throw new IOException(name + " code " + code + " was not found", e);