/* * 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 com.google.common.base.Preconditions; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.common.QName; 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.model.api.DataSchemaNode; /** * Event Stream Writer based on Normalized Node tree representation * * <h3>Writing Event Stream</h3> * * <ul> * <li><code>container</code> - Container node representation, start event is * emitted using {@link #startContainerNode(NodeIdentifier, int)} and node end event is * emitted using {@link #endNode()}. Container node is implementing * the org.opendaylight.yangtools.yang.binding.DataObject interface. * * <li><code>list</code> - YANG list statement has two representation in event * stream - unkeyed list and map. Unkeyed list is YANG list which did not * specify key. * * <ul> * <li><code>Map</code> - Map start event is emitted using * {@link #startMapNode(NodeIdentifier, int)} and is ended using {@link #endNode()}. Each map * entry start is emitted using {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)} with Map of keys * and finished using {@link #endNode()}.</li> * * <li><code>UnkeyedList</code> - Unkeyed list represent list without keys, * unkeyed list start is emitted using {@link #startUnkeyedList(NodeIdentifier, int)} list * end is emitted using {@link #endNode()}. Each list item is emitted using * {@link #startUnkeyedListItem(NodeIdentifier, int)} and ended using {@link #endNode()}.</li> * </ul></li> * * <li><code>leaf</code> - Leaf node event is emitted using * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emitted for * leaf node.</li> * * <li><code>leaf-list</code> - Leaf list start is emitted using * {@link #startLeafSet(NodeIdentifier, int)}. Leaf list end is emitted using * {@link #endNode()}. Leaf list entries are emmited using * {@link #leafSetEntryNode(QName, Object)}. * * <li><code>anyxml - AN node event is emitted using * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emitted * for anyxml node.</code></li> * * * <li><code>choice</code> Choice node event is emmited by * {@link #startChoiceNode(NodeIdentifier, int)} event and * finished by invoking {@link #endNode()} * <li> * <code>augment</code> - Represents augmentation, augmentation node is started * by invoking {@link #startAugmentationNode(AugmentationIdentifier)} and * finished by invoking {@link #endNode()}.</li> * * </ul> * * <h3>Implementation notes</h3> * * <p> * Implementations of this interface must not hold user suppled objects * and resources needlessly. * */ public interface NormalizedNodeStreamWriter extends Closeable, Flushable { /** * 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. * <p> * 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 leaf node event with supplied value. * * @param name * name of node as defined in schema, namespace and revision are * derived from parent node. * @param value * Value of leaf node. v * @throws IllegalArgumentException * If emitted leaf node has invalid value in current context or * was emitted multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void leafNode(NodeIdentifier name, Object value) throws IOException; /** * * Emits a start of leaf set (leaf-list). * <p> * Emits start of leaf set, during writing leaf set event, only * {@link #leafSetEntryNode(QName, Object)} calls are valid. Leaf set event is * finished by calling {@link #endNode()}. * * @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 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>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startLeafSet(NodeIdentifier name, int childSizeHint) throws IOException; /** * * Emits a start of leaf set (leaf-list). * <p> * Emits start of leaf set, during writing leaf set event, only * {@link #leafSetEntryNode(QName, Object)} calls are valid. Leaf set event is * finished by calling {@link #endNode()}. * * @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 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>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startOrderedLeafSet(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException; /** * Emits a leaf set entry node * * @param name * name of the node as defined in the schema. * @param value * Value of leaf set entry node. Supplied object MUST BE constant over time. * @throws IllegalArgumentException * If emitted leaf node has invalid value. * @throws IllegalStateException * If node was emitted outside <code>leaf set</code> node. * @throws IOException if an underlying IO error occurs */ void leafSetEntryNode(QName name, Object value) throws IOException; /** * * Emits start of new container. * * <p> * End of container event is emitted by invoking {@link #endNode()}. * * <p> * Valid sub-events are: * <ul> * <li>{@link #leafNode}</li> * <li>{@link #startContainerNode(NodeIdentifier, int)}</li> * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li> * <li>{@link #startLeafSet(NodeIdentifier, int)}</li> * <li>{@link #startMapNode(NodeIdentifier, int)}</li> * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li> * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li> * </ul> * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startContainerNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * * Emits start of unkeyed list node event. * * <p> * End of unkeyed list event is emitted by invoking {@link #endNode()}. * Valid subevents is only {@link #startUnkeyedListItem(NodeIdentifier, int)}. All other * methods will throw {@link IllegalArgumentException}. * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of new unkeyed list item. * * <p> * Unkeyed list item event is finished by invoking {@link #endNode()}. Valid * sub-events are: * <ul> * <li>{@link #leafNode}</li> * <li>{@link #startContainerNode(NodeIdentifier, int)}</li> * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li> * <li>{@link #startLeafSet(NodeIdentifier, int)}</li> * <li>{@link #startMapNode(NodeIdentifier, int)}</li> * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li> * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li> * </ul> * * @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 IllegalStateException * If node was emitted outside <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IOException; /** * * Emits start of map node event. * * <p> * End of map node event is emitted by invoking {@link #endNode()}. Valid * subevents is only * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}. All other * methods will throw {@link IllegalArgumentException}. * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startMapNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * * Emits start of map entry. * * <p> * End of map entry event is emitted by invoking {@link #endNode()}. * * <p> * Valid sub-events are: * <ul> * <li>{@link #leafNode}</li> * <li>{@link #startContainerNode(NodeIdentifier, int)}</li> * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li> * <li>{@link #startLeafSet(NodeIdentifier, int)}</li> * <li>{@link #startMapNode(NodeIdentifier, int)}</li> * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li> * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li> * </ul> * * * @param identifier * QName to value pairs of keys of map entry node. Values MUST BE constant over time. * @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 IllegalArgumentException * If key contains incorrect value. * @throws IllegalStateException * If node was emitted outside <code>map entry</code> node. * @throws IOException if an underlying IO error occurs */ void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException; /** * * Emits start of map node event. * * <p> * End of map node event is emitted by invoking {@link #endNode()}. Valid * subevents is only * {@link #startMapEntryNode(NodeIdentifierWithPredicates, int)}. All other * methods will throw {@link IllegalArgumentException}. * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * * * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IOException; /** * Emits start of augmentation node. * * <p> * End of augmentation event is emitted by invoking {@link #endNode()}. * * <p> * Valid sub-events are: * * <ul> * <li>{@link #leafNode}</li> * <li>{@link #startContainerNode(NodeIdentifier, int)}</li> * <li>{@link #startChoiceNode(NodeIdentifier, int)}</li> * <li>{@link #startLeafSet(NodeIdentifier, int)}</li> * <li>{@link #startMapNode(NodeIdentifier, int)}</li> * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li> * </ul> * * @param identifier * Augmentation identifier * @throws IllegalArgumentException * If augmentation is invalid in current context. * @throws IOException if an underlying IO error occurs */ void startAugmentationNode(AugmentationIdentifier identifier) throws IOException; /** * Emits anyxml node event. * * @param name * name of node as defined in schema, namespace and revision are * derived from parent node. * @param value * Value of AnyXml node. * @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>, * <code>choice</code> <code>unkeyed list</code> node. * @throws IOException if an underlying IO error occurs */ void anyxmlNode(NodeIdentifier name, Object value) throws IOException; /** * * Emits start of new yang modeled anyXml node. * * <p> * End of yang modeled anyXml node event is emitted by invoking {@link #endNode()}. * * <p> * Valid sub-events are: * <ul> * <li>{@link #leafNode}</li> * <li>{@link #startContainerNode}</li> * <li>{@link #startLeafSet}</li> * <li>{@link #startMapNode}</li> * <li>{@link #startUnkeyedList}</li> * </ul> * * @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 IllegalArgumentException * If emitted node is invalid in current context or was emitted * multiple times. * @throws IllegalStateException * If node was emitted inside <code>map</code>, * <code>choice</code> <code>unkeyed list</code> 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(@Nonnull final DataSchemaNode schema) { Preconditions.checkNotNull(schema); } @Override void close() throws IOException; @Override void flush() throws IOException; }