2 * Copyright (c) 2024 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.restconf.server.spi;
10 import static java.util.Objects.requireNonNull;
12 import java.io.Closeable;
13 import java.io.Flushable;
14 import java.io.IOException;
15 import java.util.List;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.restconf.api.query.DepthParam;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
36 * This is an experimental iterator over a {@link NormalizedNode}. This is essentially
37 * the opposite of a {@link javax.xml.stream.XMLStreamReader} -- unlike instantiating an iterator over
38 * the backing data, this encapsulates a {@link NormalizedNodeStreamWriter} and allows
39 * us to write multiple nodes.
42 public abstract class NormalizedNodeWriter implements Flushable, Closeable {
43 protected final NormalizedNodeStreamWriter writer;
45 NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
46 this.writer = requireNonNull(writer);
50 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
52 * @param writer Back-end writer
53 * @param maxDepth Maximal depth to write
54 * @return A new instance.
56 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
57 final @Nullable DepthParam maxDepth) {
58 return forStreamWriter(writer, true, maxDepth, null);
62 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
64 * @param writer Back-end writer
65 * @param maxDepth Maximal depth to write
66 * @param fields Selected child nodes to write
67 * @return A new instance.
69 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
70 final @Nullable DepthParam maxDepth, final @Nullable List<Set<QName>> fields) {
71 return forStreamWriter(writer, true, maxDepth, fields);
75 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple
76 * {@link #forStreamWriter(NormalizedNodeStreamWriter, DepthParam, List)} method, this allows the caller to
77 * switch off RFC6020 XML compliance, providing better throughput. The reason is that the XML mapping rules in
78 * RFC6020 require the encoding to emit leaf nodes which participate in a list's key first and in the order in which
79 * they are defined in the key. For JSON, this requirement is completely relaxed and leaves can be ordered in any
80 * way we see fit. The former requires a bit of work: first a lookup for each key and then for each emitted node we
81 * need to check whether it was already emitted.
83 * @param writer Back-end writer
84 * @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
85 * @param depth Maximal depth to write
86 * @param fields Selected child nodes to write
87 * @return A new instance.
89 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
90 final boolean orderKeyLeaves, final @Nullable DepthParam depth, final @Nullable List<Set<QName>> fields) {
91 return new DefaultNormalizedNodeWriter(writer, !orderKeyLeaves, depth, fields);
95 public final void flush() throws IOException {
100 public final void close() throws IOException {
106 * Iterate over the provided {@link NormalizedNode} and emit write events to the encapsulated
107 * {@link NormalizedNodeStreamWriter}.
110 * @return {@code ParameterAwareNormalizedNodeWriter}
111 * @throws IOException when thrown from the backing writer.
113 public final NormalizedNodeWriter write(final NormalizedNode node) throws IOException {
114 if (node instanceof ContainerNode n) {
116 } else if (node instanceof MapNode n) {
118 } else if (node instanceof MapEntryNode n) {
120 } else if (node instanceof LeafNode<?> n) {
122 } else if (node instanceof ChoiceNode n) {
124 } else if (node instanceof UnkeyedListNode n) {
126 } else if (node instanceof UnkeyedListEntryNode n) {
127 writeUnkeyedListEntry(n);
128 } else if (node instanceof LeafSetNode<?> n) {
130 } else if (node instanceof LeafSetEntryNode<?> n) {
131 writeLeafSetEntry(n);
132 } else if (node instanceof AnydataNode<?> n) {
134 } else if (node instanceof AnyxmlNode<?> n) {
137 throw new IOException("Unhandled contract " + node.contract().getSimpleName());
142 protected abstract void writeAnydata(AnydataNode<?> node) throws IOException;
144 protected abstract void writeAnyxml(AnyxmlNode<?> node) throws IOException;
146 protected abstract void writeChoice(ChoiceNode node) throws IOException;
148 protected abstract void writeContainer(ContainerNode node) throws IOException;
150 protected abstract void writeLeaf(LeafNode<?> node) throws IOException;
152 protected abstract void writeLeafSet(LeafSetNode<?> node) throws IOException;
154 protected abstract void writeLeafSetEntry(LeafSetEntryNode<?> node) throws IOException;
156 protected abstract void writeMap(MapNode node) throws IOException;
158 protected abstract void writeMapEntry(MapEntryNode node) throws IOException;
160 protected abstract void writeUnkeyedList(UnkeyedListNode node) throws IOException;
162 protected abstract void writeUnkeyedListEntry(UnkeyedListEntryNode node) throws IOException;