Remove Augmentation{Identifier,Node}
[yangtools.git] / codec / yang-data-codec-binfmt / src / main / java / org / opendaylight / yangtools / yang / data / codec / binfmt / NeonSR2NormalizedNodeInputStreamReader.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.codec.binfmt;
9
10 import static com.google.common.base.Verify.verify;
11
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;
19
20 /**
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.
23  */
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<>();
29
30     NeonSR2NormalizedNodeInputStreamReader(final DataInput input) {
31         super(input);
32     }
33
34     @Override
35     @Deprecated(since = "11.0.0", forRemoval = true)
36     public NormalizedNodeStreamVersion getVersion() {
37         return NormalizedNodeStreamVersion.NEON_SR2;
38     }
39
40     @Override
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);
47         };
48     }
49
50     @Override
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);
57         };
58     }
59
60     @Override
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);
69         };
70     }
71
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);
78         };
79     }
80
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));
84     }
85
86     private NodeIdentifier rawNodeIdentifier() throws IOException {
87         // Capture size before it incremented
88         final int code = codedQNames.size();
89         return storeNodeIdentifier(code, rawQName());
90     }
91
92     private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) {
93         final NodeIdentifier ret = NodeIdentifier.create(qname);
94         final int size = codedNodeIdentifiers.size();
95
96         if (code >= size) {
97             // Null-fill others
98             codedNodeIdentifiers.ensureCapacity(code + 1);
99             for (int i = size; i < code; ++i) {
100                 codedNodeIdentifiers.add(null);
101             }
102
103             codedNodeIdentifiers.add(ret);
104         } else {
105             final NodeIdentifier check = codedNodeIdentifiers.set(code, ret);
106             verify(check == null);
107         }
108
109         return ret;
110     }
111
112     private QName codedQName(final int code) throws IOException {
113         return getCode("QName", codedQNames, code);
114     }
115
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);
121         return qname;
122     }
123
124     private LegacyAugmentationIdentifier codedAugmentId(final int code) throws IOException {
125         return getCode("QName set", codedAugments, code);
126     }
127
128     private LegacyAugmentationIdentifier rawAugmentId() throws IOException {
129         final var aid = defaultReadAugmentationIdentifier();
130         codedAugments.add(aid);
131         return aid;
132     }
133
134     private QNameModule codedModule(final int code) throws IOException {
135         return getCode("Module", codedModules, code);
136     }
137
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);
143         return mod;
144     }
145
146     private static <T> T getCode(final String name, final List<T> list, final int code) throws IOException {
147         try {
148             return list.get(code);
149         } catch (IndexOutOfBoundsException e) {
150             throw new IOException(name + " code " + code + " was not found", e);
151         }
152     }
153 }