2 * Copyright (c) 2014 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.yangtools.yang.data.api.schema.stream;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import java.io.Closeable;
14 import java.io.Flushable;
15 import java.io.IOException;
16 import javax.xml.transform.dom.DOMSource;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.concepts.ExtensibleObject;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 * Event Stream Writer based on Normalized Node tree representation.
28 * <h2>Writing Event Stream</h2>
29 * Each entity is emitted by invoking its corresponding {@code start*} event, optionally followed by interior events and
30 * invoking {@link #endNode()}. Some entities supported nested entities, some do not, see below for restrictions.
33 * While this interface defines basic events, the event stream may be extended through
34 * {@link NormalizedNodeStreamWriterExtension}s discoverable through {@link #getExtensions()} method. The set of these
35 * extensions is immutable during the lifetime of a writer and may be freely cached.
38 * <li>{@code container} - Container node representation, start event is emitted using
39 * {@link #startContainerNode(NodeIdentifier, int)}.
42 * <li>{@code list} - YANG list statement has two representation in event stream - unkeyed list and map. An unkeyed
43 * list is YANG list which did not specify a {@code key} statement. A map is a {@code list} with a {@code key}
46 * <li>{@code Map} - Map start event is emitted using {@link #startMapNode(NodeIdentifier, int)}. Each map entry start
47 * is emitted using {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}.
49 * <li>{@code UnkeyedList} - Unkeyed list represent list without keys, unkeyed list start is emitted using
50 * {@link #startUnkeyedList(NodeIdentifier, int)}. Each list item is emitted using
51 * {@link #startUnkeyedListItem(NodeIdentifier, int)}.</li>
55 * <li>{@code leaf} - Leaf node start event is emitted using {@link #startLeafNode(NodeIdentifier)}. Leaf node values
56 * need to be emitted through {@link #scalarValue(Object)}.
59 * <li>{@code leaf-list} - Leaf list start is emitted using {@link #startLeafSet(NodeIdentifier, int)}. Individual
60 * leaf-list entries are emitted using {@link #startLeafSetEntryNode(NodeWithValue)}.
62 * <li>{@code anyxml} - An anyxml node event is emitted using {@link #startAnyxmlNode(NodeIdentifier, Class)}.</li>
64 * <li>{@code choice} - Choice node event is emitted by {@link #startChoiceNode(NodeIdentifier, int)} event.</li>
66 * <li>{@code augment} - Represents augmentation, augmentation node is started by invoking
67 * {@link #startAugmentationNode(AugmentationIdentifier)}.
71 * <h3>Implementation notes</h3>
74 * Implementations of this interface must not hold user suppled objects and resources needlessly.
76 public interface NormalizedNodeStreamWriter extends Closeable, Flushable,
77 ExtensibleObject<NormalizedNodeStreamWriter, NormalizedNodeStreamWriterExtension> {
79 * Methods in this interface allow users to hint the underlying implementation about the sizing of container-like
80 * constructors (leafLists, containers, etc.). These hints may be taken into account by a particular implementation
81 * to improve performance, but clients are not required to provide hints. This constant should be used by clients
82 * who either do not have the sizing information, or do not wish to divulge it (for whatever reasons).
85 * Implementations are free to ignore these hints completely, but if they do use them, they are expected to be
86 * resilient in face of missing and mismatched hints, which is to say the user can specify startLeafSet(..., 1) and
87 * then call leafNode() 15 times.
90 * The acceptable hint values are non-negative integers and this constant, all other values will result, based on
91 * implementation preference, in the hint being completely ignored or IllegalArgumentException being thrown.
93 int UNKNOWN_SIZE = -1;
96 * Emits a start of leaf node event.
98 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
99 * @throws NullPointerException if {@code name} is null
100 * @throws IllegalArgumentException If emitted leaf node was emitted multiple times.
101 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
103 * @throws IOException if an underlying IO error occurs
105 void startLeafNode(NodeIdentifier name) throws IOException;
108 * Emits a start of system-ordered leaf set (leaf-list). While this entity is open,
109 * only {@link #startLeafSetEntryNode(NodeWithValue)} calls are valid. Implementations are free to reorder entries
110 * within the leaf-list.
112 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
113 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
114 * unknown. This is only hint and should not fail writing of child events, if there are more
116 * @throws NullPointerException if {@code name} is null
117 * @throws IllegalArgumentException If emitted leaf node is invalid in current context or was emitted multiple
119 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
121 * @throws IOException if an underlying IO error occurs
123 void startLeafSet(NodeIdentifier name, int childSizeHint) throws IOException;
126 * Emits a start of a user-ordered leaf set (leaf-list). While this entity is open, only
127 * {@link #startLeafSetEntryNode(NodeWithValue)} calls are valid. Implementations must retain the same entry order.
129 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
130 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
131 * unknown. This is only hint and should not fail writing of child events, if there are more
133 * @throws NullPointerException if {@code name} is null
134 * @throws IllegalArgumentException If emitted leaf node is invalid in current context or was emitted multiple
136 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
138 * @throws IOException if an underlying IO error occurs
140 void startOrderedLeafSet(NodeIdentifier name, int childSizeHint) throws IOException;
143 * Emits a leaf set entry node.
145 * @param name name of the node as defined in the schema.
146 * @throws NullPointerException if {@code name} is null
147 * @throws IllegalArgumentException if {@code name} does not match enclosing leaf set entity
148 * @throws IllegalStateException If node was emitted outside {@code leaf set} node.
149 * @throws IOException if an underlying IO error occurs
151 void startLeafSetEntryNode(NodeWithValue<?> name) throws IOException;
154 * Emits start of new container. Valid sub-events are:
156 * <li>{@link #startLeafNode}</li>
157 * <li>{@link #startAnyxmlNode(NodeIdentifier, Class)}</li>
158 * <li>{@link #startContainerNode(NodeIdentifier, int)}</li>
159 * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li>
160 * <li>{@link #startLeafSet(NodeIdentifier, int)}</li>
161 * <li>{@link #startMapNode(NodeIdentifier, int)}</li>
162 * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li>
163 * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li>
166 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
167 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
168 * unknown. This is only hint and should not fail writing of child events, if there are more
170 * @throws NullPointerException if {@code name} is null
171 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
172 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
174 * @throws IOException if an underlying IO error occurs
176 void startContainerNode(NodeIdentifier name, int childSizeHint) throws IOException;
179 * Emits start of unkeyed list node event. Valid subevents is only
180 * {@link #startUnkeyedListItem(NodeIdentifier, int)}.
182 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
183 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
184 * unknown. This is only hint and should not fail writing of child events, if there are more
186 * @throws NullPointerException if {@code name} is null
187 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
188 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
190 * @throws IOException if an underlying IO error occurs
192 void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IOException;
195 * Emits start of new unkeyed list item. Valid sub-events are:
197 * <li>{@link #startLeafNode}</li>
198 * <li>{@link #startContainerNode(NodeIdentifier, int)}</li>
199 * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li>
200 * <li>{@link #startLeafSet(NodeIdentifier, int)}</li>
201 * <li>{@link #startMapNode(NodeIdentifier, int)}</li>
202 * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li>
203 * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li>
206 * @param name Identifier of node
207 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
208 * unknown. This is only hint and should not fail writing of child events, if there are more
210 * @throws NullPointerException if {@code name} is null
211 * @throws IllegalStateException If node was emitted outside <code>unkeyed list</code> node.
212 * @throws IOException if an underlying IO error occurs
214 void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IOException;
217 * Emits start of map node event. Valid subevent is only
218 * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}.
220 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
221 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
222 * unknown. This is only hint and should not fail writing of child events, if there are more
224 * @throws NullPointerException if {@code name} is null
225 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
226 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
228 * @throws IOException if an underlying IO error occurs
230 void startMapNode(NodeIdentifier name, int childSizeHint) throws IOException;
233 * Emits start of map entry. Valid sub-events are:
235 * <li>{@link #startLeafNode}</li>
236 * <li>{@link #startContainerNode(NodeIdentifier, int)}</li>
237 * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li>
238 * <li>{@link #startLeafSet(NodeIdentifier, int)}</li>
239 * <li>{@link #startMapNode(NodeIdentifier, int)}</li>
240 * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li>
241 * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li>
244 * @param identifier QName to value pairs of keys of map entry node.
245 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
246 * unknown. This is only hint and should not fail writing of child events, if there are more
248 * @throws NullPointerException if {@code name} is null
249 * @throws IllegalArgumentException If key contains incorrect value.
250 * @throws IllegalStateException If node was emitted outside {@code map entry} node.
251 * @throws IOException if an underlying IO error occurs
253 void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException;
256 * Emits start of map node event. Valid subevent is only
257 * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}.
259 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
260 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
261 * unknown. This is only hint and should not fail writing of child events, if there are more
263 * @throws NullPointerException if {@code name} is null
264 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
265 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
267 * @throws IOException if an underlying IO error occurs
269 void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IOException;
272 * Emits start of a choice node event.
274 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
275 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
276 * unknown. This is only hint and should not fail writing of child events, if there are more
278 * @throws NullPointerException if {@code name} is null
279 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
280 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
282 * @throws IOException if an underlying IO error occurs
284 void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IOException;
287 * Emits start of augmentation node. Valid sub-events are:
289 * <li>{@link #startLeafNode}</li>
290 * <li>{@link #startContainerNode(NodeIdentifier, int)}</li>
291 * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li>
292 * <li>{@link #startLeafSet(NodeIdentifier, int)}</li>
293 * <li>{@link #startMapNode(NodeIdentifier, int)}</li>
294 * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li>
297 * @param identifier Augmentation identifier
298 * @throws NullPointerException if {@code identifier} is null
299 * @throws IllegalArgumentException If augmentation is invalid in current context.
300 * @throws IOException if an underlying IO error occurs
302 void startAugmentationNode(AugmentationIdentifier identifier) throws IOException;
305 * Start emitting a new anydata node identified by name.
307 * @param name The name of the anydata element
308 * @param objectModel The object model of anydata content
309 * @return True if the specified object model is supported by this extension and the process of emitting the node
310 * has started. False if the object model is not supported and the node has not started to be emitted.
311 * @throws NullPointerException if any argument is null
312 * @throws IOException if an underlying IO error occurs
315 boolean startAnydataNode(NodeIdentifier name, Class<?> objectModel) throws IOException;
318 * Emits a start of anyxml node event.
320 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
321 * @param objectModel The object model of anyxml content
322 * @return True if the specified object model is supported by this extension and the process of emitting the node
323 * has started. False if the object model is not supported and the node has not started to be emitted.
324 * @throws NullPointerException if any argument is null
325 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
326 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
328 * @throws IOException if an underlying IO error occurs
330 boolean startAnyxmlNode(NodeIdentifier name, Class<?> objectModel) throws IOException;
333 * Set the value of current anyxml node. This call is only valid within the context in which an anyxml node is open.
335 * @param value node value
336 * @throws NullPointerException if the argument is null
337 * @throws IllegalArgumentException if the argument does not represents a valid value
338 * @throws IllegalStateException if an anyxml node is not open or if it's value has already been set and this
339 * implementation does not allow resetting the value.
340 * @throws IOException if an underlying IO error occurs
342 // FIXME: 7.0.0: this probably should integrated with scalarValue()
343 void domSourceValue(DOMSource value) throws IOException;
346 * Emits start of new YANG-modeled anyxml node. Valid sub-events are:
348 * <li>{@link #startLeafNode}</li>
349 * <li>{@link #startContainerNode}</li>
350 * <li>{@link #startLeafSet}</li>
351 * <li>{@link #startMapNode}</li>
352 * <li>{@link #startUnkeyedList}</li>
355 * @param name name of node as defined in schema, namespace and revision are derived from parent node.
356 * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is
357 * unknown. This is only hint and should not fail writing of child events, if there are more
359 * @throws NullPointerException if {@code name} is null
360 * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times.
361 * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list}
363 * @throws IOException if an underlying IO error occurs
365 void startYangModeledAnyXmlNode(NodeIdentifier name, int childSizeHint) throws IOException;
368 * Emits end event for node.
370 * @throws IllegalStateException If there is no start* event to be closed.
371 * @throws IOException if an underlying IO error occurs
373 void endNode() throws IOException;
376 * Attach the specified {@link DataSchemaNode} to the next node which will get started or emitted. The default
377 * implementation does nothing.
379 * @param schema DataSchemaNode
380 * @throws NullPointerException if the argument is null
382 default void nextDataSchemaNode(final @NonNull DataSchemaNode schema) {
383 requireNonNull(schema);
387 * Set the value of current node. This call is only valid within the context in which a value-bearing node is open,
388 * such as a LeafNode, LeafSetEntryNode.
390 * @param value node value, must be effectively immutable
391 * @throws NullPointerException if the argument is null
392 * @throws IllegalArgumentException if the argument does not represents a valid value
393 * @throws IllegalStateException if a value-bearing node is not open or if it's value has already been set and this
394 * implementation does not allow resetting the value.
395 * @throws IOException if an underlying IO error occurs
397 void scalarValue(@NonNull Object value) throws IOException;
400 void close() throws IOException;
403 void flush() throws IOException;