/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.data.api.schema.stream; import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import javax.xml.transform.dom.DOMSource; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.ExtensibleObject; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; /** * Event Stream Writer based on Normalized Node tree representation. * *

Writing Event Stream

* Each entity is emitted by invoking its corresponding {@code start*} event, optionally followed by interior events and * invoking {@link #endNode()}. Some entities supported nested entities, some do not, see below for restrictions. * *

* While this interface defines basic events, the event stream may be extended through * {@link NormalizedNodeStreamWriterExtension}s discoverable through {@link #getExtensions()} method. The set of these * extensions is immutable during the lifetime of a writer and may be freely cached. * *

* *

Implementation notes

* *

* Implementations of this interface must not hold user suppled objects and resources needlessly. */ public interface NormalizedNodeStreamWriter extends Closeable, Flushable, ExtensibleObject { /** * Methods in this interface allow users to hint the underlying implementation about the sizing of container-like * constructors (leafLists, containers, etc.). These hints may be taken into account by a particular implementation * to improve performance, but clients are not required to provide hints. This constant should be used by clients * who either do not have the sizing information, or do not wish to divulge it (for whatever reasons). * *

* Implementations are free to ignore these hints completely, but if they do use them, they are expected to be * resilient in face of missing and mismatched hints, which is to say the user can specify startLeafSet(..., 1) and * then call leafNode() 15 times. * *

* The acceptable hint values are non-negative integers and this constant, all other values will result, based on * implementation preference, in the hint being completely ignored or IllegalArgumentException being thrown. */ int UNKNOWN_SIZE = -1; /** * Emits a start of leaf node event. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted leaf node was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startLeafNode(NodeIdentifier name) throws IOException; /** * Emits a start of system-ordered leaf set (leaf-list). While this entity is open, * only {@link #startLeafSetEntryNode(NodeWithValue)} calls are valid. Implementations are free to reorder entries * within the leaf-list. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted leaf node is invalid in current context or was emitted multiple * times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startLeafSet(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits a start of a user-ordered leaf set (leaf-list). While this entity is open, only * {@link #startLeafSetEntryNode(NodeWithValue)} calls are valid. Implementations must retain the same entry order. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted leaf node is invalid in current context or was emitted multiple * times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startOrderedLeafSet(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits a leaf set entry node. * * @param name name of the node as defined in the schema. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException if {@code name} does not match enclosing leaf set entity * @throws IllegalStateException If node was emitted outside {@code leaf set} node. * @throws IOException if an underlying IO error occurs */ void startLeafSetEntryNode(NodeWithValue name) throws IOException; /** * Emits start of new container. Valid sub-events are: *

* * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startContainerNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of unkeyed list node event. Valid subevents is only * {@link #startUnkeyedListItem(NodeIdentifier, int)}. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of new unkeyed list item. Valid sub-events are: * * * @param name Identifier of node * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalStateException If node was emitted outside unkeyed list node. * @throws IOException if an underlying IO error occurs */ void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of map node event. Valid subevent is only * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startMapNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of map entry. Valid sub-events are: * * * @param identifier QName to value pairs of keys of map entry node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If key contains incorrect value. * @throws IllegalStateException If node was emitted outside {@code map entry} node. * @throws IOException if an underlying IO error occurs */ void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException; /** * Emits start of map node event. Valid subevent is only * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of a choice node event. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of augmentation node. Valid sub-events are: * * * @param identifier Augmentation identifier * @throws NullPointerException if {@code identifier} is null * @throws IllegalArgumentException If augmentation is invalid in current context. * @throws IOException if an underlying IO error occurs */ void startAugmentationNode(AugmentationIdentifier identifier) throws IOException; /** * Start emitting a new anydata node identified by name. * * @param name The name of the anydata element * @param objectModel The object model of anydata content * @return True if the specified object model is supported by this extension and the process of emitting the node * has started. False if the object model is not supported and the node has not started to be emitted. * @throws NullPointerException if any argument is null * @throws IOException if an underlying IO error occurs */ @Beta boolean startAnydataNode(NodeIdentifier name, Class objectModel) throws IOException; /** * Emits a start of anyxml node event. * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param objectModel The object model of anyxml content * @return True if the specified object model is supported by this extension and the process of emitting the node * has started. False if the object model is not supported and the node has not started to be emitted. * @throws NullPointerException if any argument is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ boolean startAnyxmlNode(NodeIdentifier name, Class objectModel) throws IOException; /** * Set the value of current anyxml node. This call is only valid within the context in which an anyxml node is open. * * @param value node value * @throws NullPointerException if the argument is null * @throws IllegalArgumentException if the argument does not represents a valid value * @throws IllegalStateException if an anyxml node is not open or if it's value has already been set and this * implementation does not allow resetting the value. * @throws IOException if an underlying IO error occurs */ // FIXME: 7.0.0: this probably should integrated with scalarValue() void domSourceValue(DOMSource value) throws IOException; /** * Emits start of new YANG-modeled anyxml node. Valid sub-events are: * * * @param name name of node as defined in schema, namespace and revision are derived from parent node. * @param childSizeHint Non-negative count of expected direct child nodes or {@link #UNKNOWN_SIZE} if count is * unknown. This is only hint and should not fail writing of child events, if there are more * events than count. * @throws NullPointerException if {@code name} is null * @throws IllegalArgumentException If emitted node is invalid in current context or was emitted multiple times. * @throws IllegalStateException If node was emitted inside {@code map}, {@code choice} or a {@code unkeyed list} * node. * @throws IOException if an underlying IO error occurs */ void startYangModeledAnyXmlNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits end event for node. * * @throws IllegalStateException If there is no start* event to be closed. * @throws IOException if an underlying IO error occurs */ void endNode() throws IOException; /** * Attach the specified {@link DataSchemaNode} to the next node which will get started or emitted. The default * implementation does nothing. * * @param schema DataSchemaNode * @throws NullPointerException if the argument is null */ default void nextDataSchemaNode(final @NonNull DataSchemaNode schema) { requireNonNull(schema); } /** * Set the value of current node. This call is only valid within the context in which a value-bearing node is open, * such as a LeafNode, LeafSetEntryNode. * * @param value node value, must be effectively immutable * @throws NullPointerException if the argument is null * @throws IllegalArgumentException if the argument does not represents a valid value * @throws IllegalStateException if a value-bearing node is not open or if it's value has already been set and this * implementation does not allow resetting the value. * @throws IOException if an underlying IO error occurs */ void scalarValue(@NonNull Object value) throws IOException; @Override void close() throws IOException; @Override void flush() throws IOException; }