60e076d22c6146675b2858c1642648792f17328d
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / DataNodeContainer.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.model.api;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
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 java.util.Set;
20 import javax.annotation.Nullable;
21 import org.opendaylight.yangtools.yang.common.QName;
22
23 /**
24  * Node which can contains other nodes.
25  */
26 public interface DataNodeContainer {
27     /**
28      * Returns set of all newly defined types within this DataNodeContainer.
29      *
30      * @return typedef statements in lexicographical order
31      */
32     Set<TypeDefinition<?>> getTypeDefinitions();
33
34     /**
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.
37      *
38      * <p>
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}.
42      *
43      * @return child nodes in lexicographical order
44      */
45     Collection<DataSchemaNode> getChildNodes();
46
47     /**
48      * Returns set of all groupings defined within this DataNodeContainer.
49      *
50      * @return grouping statements in lexicographical order
51      */
52     Set<GroupingDefinition> getGroupings();
53
54     /**
55      * Returns the child node corresponding to the specified name.
56      *
57      * <p>
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}.
61      *
62      * @param name QName of child
63      * @return child node of this DataNodeContainer if child with given name is present, null otherwise
64      * @deprecated Use {@link #findDataChildByName(QName)} instead.
65      * @throws NullPointerException if {@code name} is null
66      */
67     @Deprecated
68     @Nullable default DataSchemaNode getDataChildByName(final QName name) {
69         return findDataChildByName(name).orElse(null);
70     }
71
72     /**
73      * Returns the child node corresponding to the specified name.
74      *
75      * <p>
76      * Note that the nodes searched are <strong>NOT</strong> {@code data nodes}, but rather {@link DataSchemaNode}s,
77      * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children.
78      *
79      * @param name QName of child
80      * @return child node of this DataNodeContainer if child with given name is present, empty otherwise
81      * @throws NullPointerException if {@code name} is null
82      */
83     Optional<DataSchemaNode> findDataChildByName(QName name);
84
85     /**
86      * Returns grouping nodes used ny this container.
87      *
88      * @return Set of all uses nodes defined within this DataNodeContainer
89      */
90     Set<UsesNode> getUses();
91
92     /**
93      * Returns a {@code data node} identified by a QName. This method is distinct from
94      * {@link #findDataChildByName(QName)} in that it skips over {@link ChoiceSchemaNode}s and {@link CaseSchemaNode}s,
95      * hence mirroring layout of the {@code data tree}, not {@code schema tree}.
96      *
97      * @param name QName identifier of the data node
98      * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
99      * @throws NullPointerException if {@code name} is null
100      */
101     @Beta
102     default Optional<DataSchemaNode> findDataTreeChild(final QName name) {
103         // First we try to find a direct child and check if it is a data node (as per RFC7950)
104         final Optional<DataSchemaNode> optDataChild = findDataChildByName(name);
105         if (HelperMethods.isDataNode(optDataChild)) {
106             return optDataChild;
107         }
108
109         // There either is no such node present, or there are Choice/CaseSchemaNodes with the same name involved,
110         // hence we have to resort to a full search.
111         for (DataSchemaNode child : getChildNodes()) {
112             if (child instanceof ChoiceSchemaNode) {
113                 for (CaseSchemaNode choiceCase : ((ChoiceSchemaNode) child).getCases().values()) {
114                     final Optional<DataSchemaNode> caseChild = choiceCase.findDataTreeChild(name);
115                     if (caseChild.isPresent()) {
116                         return caseChild;
117                     }
118                 }
119             }
120         }
121
122         return Optional.empty();
123     }
124
125     /**
126      * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling
127      * {@link #findDataTreeChild(QName)}.
128      *
129      * @param path Series of QNames towards identifying the requested data node
130      * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
131      * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node.
132      * @throws NoSuchElementException if {@code path} is empty
133      * @throws NullPointerException if {@code path} is null or contains a null
134      */
135     @Beta
136     default Optional<DataSchemaNode> findDataTreeChild(final QName... path) {
137         return findDataTreeChild(Arrays.asList(path));
138     }
139
140     /**
141      * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling
142      * {@link #findDataTreeChild(QName)}.
143      *
144      * @param path Series of QNames towards identifying the requested data node
145      * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise
146      * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node.
147      * @throws NoSuchElementException if {@code path} is empty
148      * @throws NullPointerException if {@code path} is null or contains a null
149      */
150     @Beta
151     default Optional<DataSchemaNode> findDataTreeChild(final Iterable<QName> path) {
152         final Iterator<QName> it = path.iterator();
153         DataNodeContainer parent = this;
154         do {
155             final Optional<DataSchemaNode> optChild = parent.findDataTreeChild(requireNonNull(it.next()));
156             if (!optChild.isPresent() || !it.hasNext()) {
157                 return optChild;
158             }
159
160             final DataSchemaNode child = optChild.get();
161             checkArgument(child instanceof DataNodeContainer, "Path %s extends beyond terminal child %s", path, child);
162             parent = (DataNodeContainer) child;
163         } while (true);
164     }
165 }