2 * Copyright (c) 2013 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.model.api;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Iterator;
17 import java.util.NoSuchElementException;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.yangtools.yang.common.QName;
24 * Node which can contains other nodes.
26 public interface DataNodeContainer {
28 * Returns set of all newly defined types within this DataNodeContainer.
30 * @return typedef statements in lexicographical order
32 @NonNull Collection<? extends @NonNull TypeDefinition<?>> getTypeDefinitions();
35 * Returns set of all child nodes defined within this DataNodeContainer. Although the return type is a collection,
36 * each node is guaranteed to be present at most once.
39 * Note that the nodes returned are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
40 * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are present instead of their children. This
41 * is consistent with {@code schema tree}.
43 * @return child nodes in lexicographical order
45 @NonNull Collection<? extends @NonNull DataSchemaNode> getChildNodes();
48 * Returns set of all groupings defined within this DataNodeContainer.
50 * @return grouping statements in lexicographical order
52 @NonNull Collection<? extends @NonNull GroupingDefinition> getGroupings();
55 * Returns the child node corresponding to the specified name.
58 * Note that the nodes searched are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
59 * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. This
60 * is consistent with {@code schema tree}.
62 * @param name QName of child
63 * @return child node of this DataNodeContainer if child with given name is present, null otherwise
64 * @throws NullPointerException if {@code name} is null
66 default @Nullable DataSchemaNode dataChildByName(final QName name) {
67 return findDataChildByName(name).orElse(null);
71 * Returns the child node corresponding to the specified name.
74 * Note that the nodes searched are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
75 * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. This
76 * is consistent with {@code schema tree}.
78 * @param name QName of child
79 * @return child node of this DataNodeContainer if child with given name is present, null otherwise
80 * @deprecated Use {@link #dataChildByName(QName)} or {@link #findDataChildByName(QName)} instead. This method will
81 * be repurposed to assert existence in the next major release.
82 * @throws NullPointerException if {@code name} is null
84 @Deprecated(forRemoval = true)
85 default @Nullable DataSchemaNode getDataChildByName(final QName name) {
86 return dataChildByName(name);
90 * Returns the child node corresponding to the specified name.
93 * Note that the nodes searched are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
94 * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children.
96 * @param name QName of child
97 * @return child node of this DataNodeContainer if child with given name is present, empty otherwise
98 * @throws NullPointerException if {@code name} is null
100 Optional<DataSchemaNode> findDataChildByName(QName name);
103 * Returns the child node corresponding to the specified name.
106 * Note that the nodes searched are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
107 * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children.
109 * @param first QName of first child
110 * @param others QNames of subsequent children
111 * @return child node of this DataNodeContainer if child with given name is present, empty otherwise
112 * @throws NullPointerException if any argument is null
114 default Optional<DataSchemaNode> findDataChildByName(final QName first, final QName... others) {
115 Optional<DataSchemaNode> optCurrent = findDataChildByName(first);
116 for (QName qname : others) {
117 if (optCurrent.isPresent()) {
118 final DataSchemaNode current = optCurrent.get();
119 if (current instanceof DataNodeContainer) {
120 optCurrent = ((DataNodeContainer) current).findDataChildByName(qname);
125 return Optional.empty();
131 * Returns grouping nodes used ny this container.
133 * @return Set of all uses nodes defined within this DataNodeContainer
135 @NonNull Collection<? extends @NonNull UsesNode> getUses();
138 * Returns a {@code data node} identified by a QName. This method is distinct from
139 * {@link #findDataChildByName(QName)} in that it skips over {@link ChoiceSchemaNode}s and {@link CaseSchemaNode}s,
140 * hence mirroring layout of the {@code data tree}, not {@code schema tree}.
142 * @param name QName identifier of the data node
143 * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
144 * @throws NullPointerException if {@code name} is null
147 default Optional<DataSchemaNode> findDataTreeChild(final QName name) {
148 // First we try to find a direct child and check if it is a data node (as per RFC7950)
149 final Optional<DataSchemaNode> optDataChild = findDataChildByName(name);
150 if (HelperMethods.isDataNode(optDataChild)) {
154 // There either is no such node present, or there are Choice/CaseSchemaNodes with the same name involved,
155 // hence we have to resort to a full search.
156 for (DataSchemaNode child : getChildNodes()) {
157 if (child instanceof ChoiceSchemaNode) {
158 for (CaseSchemaNode choiceCase : ((ChoiceSchemaNode) child).getCases()) {
159 final Optional<DataSchemaNode> caseChild = choiceCase.findDataTreeChild(name);
160 if (caseChild.isPresent()) {
167 return Optional.empty();
171 * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling
172 * {@link #findDataTreeChild(QName)}.
174 * @param path Series of QNames towards identifying the requested data node
175 * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
176 * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node.
177 * @throws NoSuchElementException if {@code path} is empty
178 * @throws NullPointerException if {@code path} is null or contains a null
181 default Optional<DataSchemaNode> findDataTreeChild(final QName... path) {
182 return findDataTreeChild(Arrays.asList(path));
186 * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling
187 * {@link #findDataTreeChild(QName)}.
189 * @param path Series of QNames towards identifying the requested data node
190 * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
191 * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node.
192 * @throws NoSuchElementException if {@code path} is empty
193 * @throws NullPointerException if {@code path} is null or contains a null
196 default Optional<DataSchemaNode> findDataTreeChild(final Iterable<QName> path) {
197 final Iterator<QName> it = path.iterator();
198 DataNodeContainer parent = this;
200 final Optional<DataSchemaNode> optChild = parent.findDataTreeChild(requireNonNull(it.next()));
201 if (optChild.isEmpty() || !it.hasNext()) {
205 final DataSchemaNode child = optChild.get();
206 checkArgument(child instanceof DataNodeContainer, "Path %s extends beyond terminal child %s", path, child);
207 parent = (DataNodeContainer) child;