X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-model-api%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fmodel%2Fapi%2FDataNodeContainer.java;h=d1c7eb62be978213a5140e3fdac1d2c6abef2d5b;hb=ef3fdaaf376f44edae922a947ca827185d34ae81;hp=20b9ea4d48f7f5ba8383edc2ccce30eab4caf040;hpb=36368e8e6f9a791c355a7e61010a04e6a4f347d4;p=yangtools.git diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DataNodeContainer.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DataNodeContainer.java index 20b9ea4d48..d1c7eb62be 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DataNodeContainer.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DataNodeContainer.java @@ -1,61 +1,209 @@ -/* - * Copyright (c) 2013 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.model.api; - -import java.util.Set; - -import org.opendaylight.yangtools.yang.common.QName; - -/** - * Node which can contains other nodes. - */ -public interface DataNodeContainer { - - /** - * Returns set of all newly defined types within this DataNodeContainer. - * - * @return typedef statements in lexicographical order - */ - Set> getTypeDefinitions(); - - /** - * Returns set of all child nodes defined within this DataNodeContainer. - * - * @return child nodes in lexicographical order - */ - Set getChildNodes(); - - /** - * Returns set of all groupings defined within this DataNodeContainer. - * - * @return grouping statements in lexicographical order - */ - Set getGroupings(); - - /** - * @param name - * QName of seeked child - * @return child node of this DataNodeContainer if child with given name is - * present, null otherwise - */ - DataSchemaNode getDataChildByName(QName name); - - /** - * @param name - * name of seeked child as String - * @return child node of this DataNodeContainer if child with given name is - * present, null otherwise - */ - DataSchemaNode getDataChildByName(String name); - - /** - * @return Set of all uses nodes defined within this DataNodeContainer - */ - Set getUses(); - -} +/* + * Copyright (c) 2013 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.model.api; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * Node which can contains other nodes. + */ +public interface DataNodeContainer { + /** + * Returns set of all newly defined types within this DataNodeContainer. + * + * @return typedef statements in lexicographical order + */ + Collection> getTypeDefinitions(); + + /** + * Returns set of all child nodes defined within this DataNodeContainer. Although the return type is a collection, + * each node is guaranteed to be present at most once. + * + *

+ * Note that the nodes returned are NOT {@code data nodes}, but rather {@link DataSchemaNode}s, + * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are present instead of their children. This + * is consistent with {@code schema tree}. + * + * @return child nodes in lexicographical order + */ + Collection getChildNodes(); + + /** + * Returns set of all groupings defined within this DataNodeContainer. + * + * @return grouping statements in lexicographical order + */ + Collection getGroupings(); + + /** + * Returns the child node corresponding to the specified name. + * + *

+ * Note that the nodes searched are NOT {@code data nodes}, but rather {@link DataSchemaNode}s, + * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. This + * is consistent with {@code schema tree}. + * + * @param name QName of child + * @return child node of this DataNodeContainer if child with given name is present, null otherwise + * @throws NullPointerException if {@code name} is null + */ + default @Nullable DataSchemaNode dataChildByName(final QName name) { + return findDataChildByName(name).orElse(null); + } + + /** + * Returns the child node corresponding to the specified name. + * + *

+ * Note that the nodes searched are NOT {@code data nodes}, but rather {@link DataSchemaNode}s, + * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. This + * is consistent with {@code schema tree}. + * + * @param name QName of child + * @return child node of this DataNodeContainer if child with given name is present, null otherwise + * @throws NullPointerException if {@code name} is null + * @deprecated Use {@link #dataChildByName(QName)} or {@link #findDataChildByName(QName)} instead. This method will + * be repurposed to assert existence in the next major release. + */ + @Deprecated(forRemoval = true) + default @Nullable DataSchemaNode getDataChildByName(final QName name) { + return dataChildByName(name); + } + + /** + * Returns the child node corresponding to the specified name. + * + *

+ * Note that the nodes searched are NOT {@code data nodes}, but rather {@link DataSchemaNode}s, + * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. + * + * @param name QName of child + * @return child node of this DataNodeContainer if child with given name is present, empty otherwise + * @throws NullPointerException if {@code name} is null + */ + Optional findDataChildByName(QName name); + + /** + * Returns the child node corresponding to the specified name. + * + *

+ * Note that the nodes searched are NOT {@code data nodes}, but rather {@link DataSchemaNode}s, + * hence {@link ChoiceSchemaNode} and {@link CaseSchemaNode} are returned instead of their matching children. + * + * @param first QName of first child + * @param others QNames of subsequent children + * @return child node of this DataNodeContainer if child with given name is present, empty otherwise + * @throws NullPointerException if any argument is null + */ + default Optional findDataChildByName(final QName first, final QName... others) { + Optional optCurrent = findDataChildByName(first); + for (QName qname : others) { + if (optCurrent.isPresent()) { + final DataSchemaNode current = optCurrent.get(); + if (current instanceof DataNodeContainer) { + optCurrent = ((DataNodeContainer) current).findDataChildByName(qname); + continue; + } + } + + return Optional.empty(); + } + return optCurrent; + } + + /** + * Returns grouping nodes used ny this container. + * + * @return Set of all uses nodes defined within this DataNodeContainer + */ + Collection getUses(); + + /** + * Returns a {@code data node} identified by a QName. This method is distinct from + * {@link #findDataChildByName(QName)} in that it skips over {@link ChoiceSchemaNode}s and {@link CaseSchemaNode}s, + * hence mirroring layout of the {@code data tree}, not {@code schema tree}. + * + * @param name QName identifier of the data node + * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise + * @throws NullPointerException if {@code name} is null + */ + @Beta + default Optional findDataTreeChild(final QName name) { + // First we try to find a direct child and check if it is a data node (as per RFC7950) + final Optional optDataChild = findDataChildByName(name); + if (HelperMethods.isDataNode(optDataChild)) { + return optDataChild; + } + + // There either is no such node present, or there are Choice/CaseSchemaNodes with the same name involved, + // hence we have to resort to a full search. + for (DataSchemaNode child : getChildNodes()) { + if (child instanceof ChoiceSchemaNode) { + for (CaseSchemaNode choiceCase : ((ChoiceSchemaNode) child).getCases()) { + final Optional caseChild = choiceCase.findDataTreeChild(name); + if (caseChild.isPresent()) { + return caseChild; + } + } + } + } + + return Optional.empty(); + } + + /** + * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling + * {@link #findDataTreeChild(QName)}. + * + * @param path Series of QNames towards identifying the requested data node + * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise + * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node. + * @throws NoSuchElementException if {@code path} is empty + * @throws NullPointerException if {@code path} is null or contains a null + */ + @Beta + default Optional findDataTreeChild(final QName... path) { + return findDataTreeChild(Arrays.asList(path)); + } + + /** + * Returns a {@code data node} identified by a series of QNames. This is equivalent to incrementally calling + * {@link #findDataTreeChild(QName)}. + * + * @param path Series of QNames towards identifying the requested data node + * @return Direct or indirect child of this DataNodeContainer which is a {@code data node}, empty otherwise + * @throws IllegalArgumentException if {@code path} is determined to go beyond a not-container-nor-list node. + * @throws NoSuchElementException if {@code path} is empty + * @throws NullPointerException if {@code path} is null or contains a null + */ + @Beta + default Optional findDataTreeChild(final Iterable path) { + final Iterator it = path.iterator(); + DataNodeContainer parent = this; + do { + final Optional optChild = parent.findDataTreeChild(requireNonNull(it.next())); + if (optChild.isEmpty() || !it.hasNext()) { + return optChild; + } + + final DataSchemaNode child = optChild.get(); + checkArgument(child instanceof DataNodeContainer, "Path %s extends beyond terminal child %s", path, child); + parent = (DataNodeContainer) child; + } while (true); + } +}