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.restconf.server.spi.DefaultNormalizedNodeWriter.OrderedRestconfNormalizedNodeWriter;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
37 * This is an experimental iterator over a {@link NormalizedNode}. This is essentially
38 * the opposite of a {@link javax.xml.stream.XMLStreamReader} -- unlike instantiating an iterator over
39 * the backing data, this encapsulates a {@link NormalizedNodeStreamWriter} and allows
40 * us to write multiple nodes.
43 public abstract class NormalizedNodeWriter implements Flushable, Closeable {
44 protected final NormalizedNodeStreamWriter writer;
46 NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
47 this.writer = requireNonNull(writer);
51 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
53 * @param writer Back-end writer
54 * @param maxDepth Maximal depth to write
55 * @return A new instance.
57 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
58 final @Nullable DepthParam maxDepth) {
59 return forStreamWriter(writer, true, maxDepth, null);
63 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
65 * @param writer Back-end writer
66 * @param maxDepth Maximal depth to write
67 * @param fields Selected child nodes to write
68 * @return A new instance.
70 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
71 final @Nullable DepthParam maxDepth, final @Nullable List<Set<QName>> fields) {
72 return forStreamWriter(writer, true, maxDepth, fields);
76 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple
77 * {@link #forStreamWriter(NormalizedNodeStreamWriter, DepthParam, List)} method, this allows the caller to
78 * switch off RFC6020 XML compliance, providing better throughput. The reason is that the XML mapping rules in
79 * RFC6020 require the encoding to emit leaf nodes which participate in a list's key first and in the order in which
80 * they are defined in the key. For JSON, this requirement is completely relaxed and leaves can be ordered in any
81 * way we see fit. The former requires a bit of work: first a lookup for each key and then for each emitted node we
82 * need to check whether it was already emitted.
84 * @param writer Back-end writer
85 * @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
86 * @param depth Maximal depth to write
87 * @param fields Selected child nodes to write
88 * @return A new instance.
90 public static final NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
91 final boolean orderKeyLeaves, final @Nullable DepthParam depth, final @Nullable List<Set<QName>> fields) {
92 return orderKeyLeaves ? new OrderedRestconfNormalizedNodeWriter(writer, depth, fields)
93 : new DefaultNormalizedNodeWriter(writer, depth, fields);
97 public final void flush() throws IOException {
102 public final void close() throws IOException {
108 * Iterate over the provided {@link NormalizedNode} and emit write events to the encapsulated
109 * {@link NormalizedNodeStreamWriter}.
112 * @return {@code ParameterAwareNormalizedNodeWriter}
113 * @throws IOException when thrown from the backing writer.
115 public final NormalizedNodeWriter write(final NormalizedNode node) throws IOException {
116 if (node instanceof ContainerNode n) {
118 } else if (node instanceof MapNode n) {
120 } else if (node instanceof MapEntryNode n) {
122 } else if (node instanceof LeafNode<?> n) {
124 } else if (node instanceof ChoiceNode n) {
126 } else if (node instanceof UnkeyedListNode n) {
128 } else if (node instanceof UnkeyedListEntryNode n) {
129 writeUnkeyedListEntry(n);
130 } else if (node instanceof LeafSetNode<?> n) {
132 } else if (node instanceof LeafSetEntryNode<?> n) {
133 writeLeafSetEntry(n);
134 } else if (node instanceof AnydataNode<?> n) {
136 } else if (node instanceof AnyxmlNode<?> n) {
139 throw new IOException("Unhandled contract " + node.contract().getSimpleName());
144 protected abstract void writeAnydata(AnydataNode<?> node) throws IOException;
146 protected abstract void writeAnyxml(AnyxmlNode<?> node) throws IOException;
148 protected abstract void writeChoice(ChoiceNode node) throws IOException;
150 protected abstract void writeContainer(ContainerNode node) throws IOException;
152 protected abstract void writeLeaf(LeafNode<?> node) throws IOException;
154 protected abstract void writeLeafSet(LeafSetNode<?> node) throws IOException;
156 protected abstract void writeLeafSetEntry(LeafSetEntryNode<?> node) throws IOException;
158 protected abstract void writeMap(MapNode node) throws IOException;
160 protected abstract void writeMapEntry(MapEntryNode node) throws IOException;
162 protected abstract void writeUnkeyedList(UnkeyedListNode node) throws IOException;
164 protected abstract void writeUnkeyedListEntry(UnkeyedListEntryNode node) throws IOException;