2 * Copyright (c) 2015 Cisco Systems, Inc. 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.controller.cluster.datastore.node.utils.stream;
10 import com.google.common.base.Preconditions;
11 import java.io.DataOutput;
12 import java.io.IOException;
13 import java.io.OutputStream;
14 import java.nio.charset.StandardCharsets;
15 import java.util.Collection;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
22 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 abstract class AbstractNormalizedNodeDataOutput implements NormalizedNodeDataOutput, NormalizedNodeStreamWriter {
27 private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodeDataOutput.class);
29 private final DataOutput output;
31 private NormalizedNodeWriter normalizedNodeWriter;
32 private boolean headerWritten;
33 private QName lastLeafSetQName;
35 AbstractNormalizedNodeDataOutput(final DataOutput output) {
36 this.output = Preconditions.checkNotNull(output);
39 private void ensureHeaderWritten() throws IOException {
41 output.writeByte(TokenTypes.SIGNATURE_MARKER);
42 output.writeShort(streamVersion());
47 protected abstract short streamVersion();
48 protected abstract void writeQName(QName qname) throws IOException;
49 protected abstract void writeString(String string) throws IOException;
52 public final void write(final int b) throws IOException {
53 ensureHeaderWritten();
58 public final void write(final byte[] b) throws IOException {
59 ensureHeaderWritten();
64 public final void write(final byte[] b, final int off, final int len) throws IOException {
65 ensureHeaderWritten();
66 output.write(b, off, len);
70 public final void writeBoolean(final boolean v) throws IOException {
71 ensureHeaderWritten();
72 output.writeBoolean(v);
76 public final void writeByte(final int v) throws IOException {
77 ensureHeaderWritten();
82 public final void writeShort(final int v) throws IOException {
83 ensureHeaderWritten();
88 public final void writeChar(final int v) throws IOException {
89 ensureHeaderWritten();
94 public final void writeInt(final int v) throws IOException {
95 ensureHeaderWritten();
100 public final void writeLong(final long v) throws IOException {
101 ensureHeaderWritten();
106 public final void writeFloat(final float v) throws IOException {
107 ensureHeaderWritten();
108 output.writeFloat(v);
112 public final void writeDouble(final double v) throws IOException {
113 ensureHeaderWritten();
114 output.writeDouble(v);
118 public final void writeBytes(final String s) throws IOException {
119 ensureHeaderWritten();
120 output.writeBytes(s);
124 public final void writeChars(final String s) throws IOException {
125 ensureHeaderWritten();
126 output.writeChars(s);
130 public final void writeUTF(final String s) throws IOException {
131 ensureHeaderWritten();
135 private NormalizedNodeWriter normalizedNodeWriter() {
136 if(normalizedNodeWriter == null) {
137 normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(this);
140 return normalizedNodeWriter;
144 public void writeNormalizedNode(final NormalizedNode<?, ?> node) throws IOException {
145 ensureHeaderWritten();
146 normalizedNodeWriter().write(node);
150 public void leafNode(final YangInstanceIdentifier.NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
151 Preconditions.checkNotNull(name, "Node identifier should not be null");
152 LOG.debug("Writing a new leaf node");
153 startNode(name.getNodeType(), NodeTypes.LEAF_NODE);
159 public void startLeafSet(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
160 Preconditions.checkNotNull(name, "Node identifier should not be null");
161 LOG.debug("Starting a new leaf set");
163 lastLeafSetQName = name.getNodeType();
164 startNode(name.getNodeType(), NodeTypes.LEAF_SET);
168 public void startOrderedLeafSet(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
169 Preconditions.checkNotNull(name, "Node identifier should not be null");
170 LOG.debug("Starting a new ordered leaf set");
172 lastLeafSetQName = name.getNodeType();
173 startNode(name.getNodeType(), NodeTypes.ORDERED_LEAF_SET);
177 public void leafSetEntryNode(final QName name, final Object value) throws IOException, IllegalArgumentException {
178 LOG.debug("Writing a new leaf set entry node");
180 output.writeByte(NodeTypes.LEAF_SET_ENTRY_NODE);
182 // lastLeafSetQName is set if the parent LeafSetNode was previously written. Otherwise this is a
183 // stand alone LeafSetEntryNode so write out it's name here.
184 if(lastLeafSetQName == null) {
192 public void startContainerNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
193 Preconditions.checkNotNull(name, "Node identifier should not be null");
195 LOG.debug("Starting a new container node");
197 startNode(name.getNodeType(), NodeTypes.CONTAINER_NODE);
201 public void startYangModeledAnyXmlNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
202 Preconditions.checkNotNull(name, "Node identifier should not be null");
204 LOG.debug("Starting a new yang modeled anyXml node");
206 startNode(name.getNodeType(), NodeTypes.YANG_MODELED_ANY_XML_NODE);
210 public void startUnkeyedList(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
211 Preconditions.checkNotNull(name, "Node identifier should not be null");
212 LOG.debug("Starting a new unkeyed list");
214 startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST);
218 public void startUnkeyedListItem(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalStateException {
219 Preconditions.checkNotNull(name, "Node identifier should not be null");
220 LOG.debug("Starting a new unkeyed list item");
222 startNode(name.getNodeType(), NodeTypes.UNKEYED_LIST_ITEM);
226 public void startMapNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
227 Preconditions.checkNotNull(name, "Node identifier should not be null");
228 LOG.debug("Starting a new map node");
230 startNode(name.getNodeType(), NodeTypes.MAP_NODE);
234 public void startMapEntryNode(final YangInstanceIdentifier.NodeIdentifierWithPredicates identifier, final int childSizeHint) throws IOException, IllegalArgumentException {
235 Preconditions.checkNotNull(identifier, "Node identifier should not be null");
236 LOG.debug("Starting a new map entry node");
237 startNode(identifier.getNodeType(), NodeTypes.MAP_ENTRY_NODE);
239 writeKeyValueMap(identifier.getKeyValues());
244 public void startOrderedMapNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
245 Preconditions.checkNotNull(name, "Node identifier should not be null");
246 LOG.debug("Starting a new ordered map node");
248 startNode(name.getNodeType(), NodeTypes.ORDERED_MAP_NODE);
252 public void startChoiceNode(final YangInstanceIdentifier.NodeIdentifier name, final int childSizeHint) throws IOException, IllegalArgumentException {
253 Preconditions.checkNotNull(name, "Node identifier should not be null");
254 LOG.debug("Starting a new choice node");
256 startNode(name.getNodeType(), NodeTypes.CHOICE_NODE);
260 public void startAugmentationNode(final YangInstanceIdentifier.AugmentationIdentifier identifier) throws IOException, IllegalArgumentException {
261 Preconditions.checkNotNull(identifier, "Node identifier should not be null");
262 LOG.debug("Starting a new augmentation node");
264 output.writeByte(NodeTypes.AUGMENTATION_NODE);
265 writeQNameSet(identifier.getPossibleChildNames());
269 public void anyxmlNode(final YangInstanceIdentifier.NodeIdentifier name, final Object value) throws IOException, IllegalArgumentException {
270 Preconditions.checkNotNull(name, "Node identifier should not be null");
271 LOG.debug("Writing a new xml node");
273 startNode(name.getNodeType(), NodeTypes.ANY_XML_NODE);
279 public void endNode() throws IOException, IllegalStateException {
280 LOG.debug("Ending the node");
282 output.writeByte(NodeTypes.END_NODE);
286 public void close() throws IOException {
291 public void flush() throws IOException {
292 if (output instanceof OutputStream) {
293 ((OutputStream)output).flush();
297 private void startNode(final QName qName, final byte nodeType) throws IOException {
299 Preconditions.checkNotNull(qName, "QName of node identifier should not be null.");
301 ensureHeaderWritten();
303 // First write the type of node
304 output.writeByte(nodeType);
309 private void writeObjSet(final Set<?> set) throws IOException {
310 output.writeInt(set.size());
311 for (Object o : set) {
312 Preconditions.checkArgument(o instanceof String, "Expected value type to be String but was %s (%s)",
315 writeString((String) o);
320 public void writeYangInstanceIdentifier(final YangInstanceIdentifier identifier) throws IOException {
321 ensureHeaderWritten();
322 writeYangInstanceIdentifierInternal(identifier);
325 private void writeYangInstanceIdentifierInternal(final YangInstanceIdentifier identifier) throws IOException {
326 Collection<YangInstanceIdentifier.PathArgument> pathArguments = identifier.getPathArguments();
327 output.writeInt(pathArguments.size());
329 for(YangInstanceIdentifier.PathArgument pathArgument : pathArguments) {
330 writePathArgument(pathArgument);
335 public void writePathArgument(final YangInstanceIdentifier.PathArgument pathArgument) throws IOException {
337 byte type = PathArgumentTypes.getSerializablePathArgumentType(pathArgument);
339 output.writeByte(type);
342 case PathArgumentTypes.NODE_IDENTIFIER:
344 YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
345 (YangInstanceIdentifier.NodeIdentifier) pathArgument;
347 writeQName(nodeIdentifier.getNodeType());
350 case PathArgumentTypes.NODE_IDENTIFIER_WITH_PREDICATES:
352 YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
353 (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
354 writeQName(nodeIdentifierWithPredicates.getNodeType());
356 writeKeyValueMap(nodeIdentifierWithPredicates.getKeyValues());
359 case PathArgumentTypes.NODE_IDENTIFIER_WITH_VALUE :
361 YangInstanceIdentifier.NodeWithValue nodeWithValue =
362 (YangInstanceIdentifier.NodeWithValue) pathArgument;
364 writeQName(nodeWithValue.getNodeType());
365 writeObject(nodeWithValue.getValue());
368 case PathArgumentTypes.AUGMENTATION_IDENTIFIER :
370 YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier =
371 (YangInstanceIdentifier.AugmentationIdentifier) pathArgument;
373 // No Qname in augmentation identifier
374 writeQNameSet(augmentationIdentifier.getPossibleChildNames());
377 throw new IllegalStateException("Unknown node identifier type is found : " + pathArgument.getClass().toString() );
381 private void writeKeyValueMap(final Map<QName, Object> keyValueMap) throws IOException {
382 if (keyValueMap != null && !keyValueMap.isEmpty()) {
383 output.writeInt(keyValueMap.size());
385 for (QName qName : keyValueMap.keySet()) {
387 writeObject(keyValueMap.get(qName));
394 private void writeQNameSet(final Set<QName> children) throws IOException {
395 // Write each child's qname separately, if list is empty send count as 0
396 if (children != null && !children.isEmpty()) {
397 output.writeInt(children.size());
398 for (QName qName : children) {
402 LOG.debug("augmentation node does not have any child");
407 private void writeObject(final Object value) throws IOException {
409 byte type = ValueTypes.getSerializableType(value);
410 // Write object type first
411 output.writeByte(type);
414 case ValueTypes.BOOL_TYPE:
415 output.writeBoolean((Boolean) value);
417 case ValueTypes.QNAME_TYPE:
418 writeQName((QName) value);
420 case ValueTypes.INT_TYPE:
421 output.writeInt((Integer) value);
423 case ValueTypes.BYTE_TYPE:
424 output.writeByte((Byte) value);
426 case ValueTypes.LONG_TYPE:
427 output.writeLong((Long) value);
429 case ValueTypes.SHORT_TYPE:
430 output.writeShort((Short) value);
432 case ValueTypes.BITS_TYPE:
433 writeObjSet((Set<?>) value);
435 case ValueTypes.BINARY_TYPE:
436 byte[] bytes = (byte[]) value;
437 output.writeInt(bytes.length);
440 case ValueTypes.YANG_IDENTIFIER_TYPE:
441 writeYangInstanceIdentifierInternal((YangInstanceIdentifier) value);
443 case ValueTypes.NULL_TYPE :
445 case ValueTypes.STRING_BYTES_TYPE:
446 final byte[] valueBytes = value.toString().getBytes(StandardCharsets.UTF_8);
447 output.writeInt(valueBytes.length);
448 output.write(valueBytes);
451 output.writeUTF(value.toString());