X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fschema%2FSchemaUtils.java;h=a93ff38ebdd7754b1b162aed00d6046112fb284f;hb=bb60da5fe2d1928defb46ed92b290cfff93dcd81;hp=a5c5148548418596d13c1ef26543aa89c527aff4;hpb=c4dc5b33e7d24670b59cc81b65e15b37a3268608;p=yangtools.git diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java index a5c5148548..a93ff38ebd 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/SchemaUtils.java @@ -7,56 +7,69 @@ */ package org.opendaylight.yangtools.yang.data.impl.schema; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + import com.google.common.collect.Collections2; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.util.Collections; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; -import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; -import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer; +import org.opendaylight.yangtools.yang.model.api.OperationDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; public final class SchemaUtils { - private SchemaUtils() { + // Hidden on purpose } /** - * @param qname - schema node to find - * @param dataSchemaNode - iterable of schemaNodes to look through - * @return - schema node with newest revision or absent if no schema node with matching qname is found + * Find the first schema with specified QName. + * + * @param qname schema node to find + * @param dataSchemaNode Iterable of schemaNodes to look through + * @return schema node with newest revision or absent if no schema node with matching qname is found */ - public static final Optional findFirstSchema(final QName qname, final Iterable dataSchemaNode) { - DataSchemaNode sNode = null; + public static Optional findFirstSchema(final QName qname, + final Iterable dataSchemaNode) { + DataSchemaNode schema = null; if (dataSchemaNode != null && qname != null) { - for (DataSchemaNode dsn : dataSchemaNode) { + for (final DataSchemaNode dsn : dataSchemaNode) { if (qname.isEqualWithoutRevision(dsn.getQName())) { - if (sNode == null || sNode.getQName().getRevision().compareTo(dsn.getQName().getRevision()) < 0) { - sNode = dsn; + if (schema == null || Revision.compare(schema.getQName().getRevision(), + dsn.getQName().getRevision()) < 0) { + schema = dsn; } } else if (dsn instanceof ChoiceSchemaNode) { - for (ChoiceCaseNode choiceCase : ((ChoiceSchemaNode) dsn).getCases()) { - - final DataSchemaNode dataChildByName = choiceCase.getDataChildByName(qname); - if (dataChildByName != null) { - return Optional.of(dataChildByName); + for (final CaseSchemaNode choiceCase : ((ChoiceSchemaNode) dsn).getCases()) { + final Optional dataChildByName = choiceCase.findDataChildByName(qname); + if (dataChildByName.isPresent()) { + return dataChildByName; } - Optional foundDsn = findFirstSchema(qname, choiceCase.getChildNodes()); + final Optional foundDsn = findFirstSchema(qname, choiceCase.getChildNodes()); if (foundDsn.isPresent()) { return foundDsn; } @@ -64,12 +77,11 @@ public final class SchemaUtils { } } } - return Optional.fromNullable(sNode); + return Optional.ofNullable(schema); } /** - * - * Find child schema node identified by its QName within a provided schema node + * Find child schema node identified by its QName within a provided schema node. * * @param schema schema for parent node - search root * @param qname qname(with or without a revision) of a child node to be found in the parent schema @@ -77,96 +89,94 @@ public final class SchemaUtils { * @throws java.lang.IllegalStateException if the child was not found in parent schema node */ public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname) { - // Try to find child schema node directly, but use a fallback that compares QNames without revisions and auto-expands choices - final DataSchemaNode dataChildByName = schema.getDataChildByName(qname); - return dataChildByName == null ? findSchemaForChild(schema, qname, schema.getChildNodes()) : dataChildByName; + // Try to find child schema node directly, but use a fallback that compares QNames without revisions + // and auto-expands choices + final Optional dataChildByName = schema.findDataChildByName(qname); + return dataChildByName.isPresent() ? dataChildByName.get() + : findSchemaForChild(schema, qname, schema.getChildNodes()); } - @Nullable - public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, final boolean strictMode) { + public static @Nullable DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, + final boolean strictMode) { if (strictMode) { return findSchemaForChild(schema, qname); } - Optional childSchemaOptional = findFirstSchema(qname, schema.getChildNodes()); + final Optional childSchemaOptional = findFirstSchema(qname, schema.getChildNodes()); if (!childSchemaOptional.isPresent()) { return null; } return childSchemaOptional.get(); } - public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, final Iterable childNodes) { - Optional childSchema = findFirstSchema(qname, childNodes); - Preconditions.checkState(childSchema.isPresent(), - "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, schema); + public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, + final Iterable childNodes) { + final Optional childSchema = findFirstSchema(qname, childNodes); + checkState(childSchema.isPresent(), "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, + schema); return childSchema.get(); } - public static AugmentationSchema findSchemaForAugment(final AugmentationTarget schema, final Set qNames) { - Optional schemaForAugment = findAugment(schema, qNames); - Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s", - qNames, schema); - return schemaForAugment.get(); - } - - public static AugmentationSchema findSchemaForAugment(final ChoiceSchemaNode schema, final Set qNames) { - Optional schemaForAugment = Optional.absent(); - - for (ChoiceCaseNode choiceCaseNode : schema.getCases()) { - schemaForAugment = findAugment(choiceCaseNode, qNames); - if(schemaForAugment.isPresent()) { - break; + public static DataSchemaNode findSchemaForChild(final ChoiceSchemaNode schema, final QName childPartialQName) { + for (final CaseSchemaNode choiceCaseNode : schema.getCases()) { + final Optional childSchema = findFirstSchema(childPartialQName, + choiceCaseNode.getChildNodes()); + if (childSchema.isPresent()) { + return childSchema.get(); } } - Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s", - qNames, schema); - return schemaForAugment.get(); - } - private static Optional findAugment(final AugmentationTarget schema, final Set qNames) { - for (AugmentationSchema augment : schema.getAvailableAugmentations()) { + throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s", + childPartialQName, schema)); + } - HashSet qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function() { - @Override - public QName apply(final @Nonnull DataSchemaNode input) { - Preconditions.checkNotNull(input); - return input.getQName(); - } - })); + public static AugmentationSchemaNode findSchemaForAugment(final AugmentationTarget schema, + final Set qnames) { + final Optional schemaForAugment = findAugment(schema, qnames); + checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s", + qnames, schema); + return schemaForAugment.get(); + } - if(qNamesFromAugment.equals(qNames)) { - return Optional.of(augment); + public static AugmentationSchemaNode findSchemaForAugment(final ChoiceSchemaNode schema, final Set qnames) { + for (final CaseSchemaNode choiceCaseNode : schema.getCases()) { + final Optional schemaForAugment = findAugment(choiceCaseNode, qnames); + if (schemaForAugment.isPresent()) { + return schemaForAugment.get(); } } - return Optional.absent(); + throw new IllegalStateException(String.format("Unknown augmentation node detected, identified by: %s, in: %s", + qnames, schema)); } - public static DataSchemaNode findSchemaForChild(final ChoiceSchemaNode schema, final QName childPartialQName) { - for (ChoiceCaseNode choiceCaseNode : schema.getCases()) { - Optional childSchema = findFirstSchema(childPartialQName, choiceCaseNode.getChildNodes()); - if (childSchema.isPresent()) { - return childSchema.get(); + private static Optional findAugment(final AugmentationTarget schema, + final Set qnames) { + for (final AugmentationSchemaNode augment : schema.getAvailableAugmentations()) { + final Set qNamesFromAugment = ImmutableSet.copyOf(Collections2.transform(augment.getChildNodes(), + DataSchemaNode::getQName)); + if (qnames.equals(qNamesFromAugment)) { + return Optional.of(augment); } } - - throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s", - childPartialQName, schema)); + return Optional.empty(); } /** * Recursively find all child nodes that come from choices. * + * @param schema schema * @return Map with all child nodes, to their most top augmentation */ public static Map mapChildElementsFromChoices(final DataNodeContainer schema) { return mapChildElementsFromChoices(schema, schema.getChildNodes()); } - private static Map mapChildElementsFromChoices(final DataNodeContainer schema, final Iterable childNodes) { - Map mappedChoices = Maps.newLinkedHashMap(); + private static Map mapChildElementsFromChoices(final DataNodeContainer schema, + final Iterable childNodes) { + final Map mappedChoices = new LinkedHashMap<>(); for (final DataSchemaNode childSchema : childNodes) { if (childSchema instanceof ChoiceSchemaNode) { @@ -175,10 +185,9 @@ public final class SchemaUtils { continue; } - for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { - - for (QName qName : getChildNodesRecursive(choiceCaseNode)) { - mappedChoices.put(qName, (ChoiceSchemaNode) childSchema); + for (final CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { + for (final QName qname : getChildNodesRecursive(choiceCaseNode)) { + mappedChoices.put(qname, (ChoiceSchemaNode) childSchema); } } } @@ -192,8 +201,8 @@ public final class SchemaUtils { return false; } - for (AugmentationSchema augmentationSchema : ((AugmentationTarget) schema).getAvailableAugmentations()) { - if(augmentationSchema.getDataChildByName(childSchema.getQName()) != null) { + for (final AugmentationSchemaNode augmentation : ((AugmentationTarget) schema).getAvailableAugmentations()) { + if (augmentation.findDataChildByName(childSchema.getQName()).isPresent()) { return true; } } @@ -204,16 +213,17 @@ public final class SchemaUtils { /** * Recursively find all child nodes that come from augmentations. * + * @param schema schema * @return Map with all child nodes, to their most top augmentation */ - public static Map mapChildElementsFromAugments(final AugmentationTarget schema) { + public static Map mapChildElementsFromAugments(final AugmentationTarget schema) { - Map childNodesToAugmentation = Maps.newLinkedHashMap(); + final Map childNodesToAugmentation = new LinkedHashMap<>(); // Find QNames of augmented child nodes - Map augments = Maps.newHashMap(); - for (final AugmentationSchema augmentationSchema : schema.getAvailableAugmentations()) { - for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) { + final Map augments = new HashMap<>(); + for (final AugmentationSchemaNode augmentationSchema : schema.getAvailableAugmentations()) { + for (final DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) { augments.put(dataSchemaNode.getQName(), augmentationSchema); } } @@ -222,23 +232,23 @@ public final class SchemaUtils { // because nodes from augment do not contain nodes from other augmentations if (schema instanceof DataNodeContainer) { - for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) { + for (final DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) { // If is not augmented child, continue - if (!(augments.containsKey(child.getQName()))) { + if (!augments.containsKey(child.getQName())) { continue; } - AugmentationSchema mostTopAugmentation = augments.get(child.getQName()); + final AugmentationSchemaNode mostTopAugmentation = augments.get(child.getQName()); // recursively add all child nodes in case of augment, case and choice - if (child instanceof AugmentationSchema || child instanceof ChoiceCaseNode) { - for (QName qName : getChildNodesRecursive((DataNodeContainer) child)) { - childNodesToAugmentation.put(qName, mostTopAugmentation); + if (child instanceof AugmentationSchemaNode || child instanceof CaseSchemaNode) { + for (final QName qname : getChildNodesRecursive((DataNodeContainer) child)) { + childNodesToAugmentation.put(qname, mostTopAugmentation); } } else if (child instanceof ChoiceSchemaNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) child).getCases()) { - for (QName qName : getChildNodesRecursive(choiceCaseNode)) { - childNodesToAugmentation.put(qName, mostTopAugmentation); + for (final CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) child).getCases()) { + for (final QName qname : getChildNodesRecursive(choiceCaseNode)) { + childNodesToAugmentation.put(qname, mostTopAugmentation); } } } else { @@ -249,13 +259,13 @@ public final class SchemaUtils { // Choice Node has to map child nodes from all its cases if (schema instanceof ChoiceSchemaNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) schema).getCases()) { - if (!(augments.containsKey(choiceCaseNode.getQName()))) { + for (final CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) schema).getCases()) { + if (!augments.containsKey(choiceCaseNode.getQName())) { continue; } - for (QName qName : getChildNodesRecursive(choiceCaseNode)) { - childNodesToAugmentation.put(qName, augments.get(choiceCaseNode.getQName())); + for (final QName qname : getChildNodesRecursive(choiceCaseNode)) { + childNodesToAugmentation.put(qname, augments.get(choiceCaseNode.getQName())); } } } @@ -264,22 +274,22 @@ public final class SchemaUtils { } /** - * Recursively list all child nodes. + * Recursively list all child nodes. In case of choice, augment and cases, step in. * - * In case of choice, augment and cases, step in. + * @param nodeContainer node container + * @return set of QNames */ public static Set getChildNodesRecursive(final DataNodeContainer nodeContainer) { - Set allChildNodes = Sets.newHashSet(); + final Set allChildNodes = new HashSet<>(); - for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) { - if(childSchema instanceof ChoiceSchemaNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { + for (final DataSchemaNode childSchema : nodeContainer.getChildNodes()) { + if (childSchema instanceof ChoiceSchemaNode) { + for (final CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { allChildNodes.addAll(getChildNodesRecursive(choiceCaseNode)); } - } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) { + } else if (childSchema instanceof AugmentationSchemaNode || childSchema instanceof CaseSchemaNode) { allChildNodes.addAll(getChildNodesRecursive((DataNodeContainer) childSchema)); - } - else { + } else { allChildNodes.add(childSchema.getQName()); } } @@ -290,23 +300,27 @@ public final class SchemaUtils { /** * Retrieves real schemas for augmented child node. * + *

* Schema of the same child node from augment, and directly from target is not the same. * Schema of child node from augment is incomplete, therefore its useless for XML/NormalizedNode translation. * + * @param targetSchema target schema + * @param augmentSchema augment schema + * @return set of nodes */ - public static Set getRealSchemasForAugment(final AugmentationTarget targetSchema, final AugmentationSchema augmentSchema) { - if (!(targetSchema.getAvailableAugmentations().contains(augmentSchema))) { - return Collections.emptySet(); + public static Set getRealSchemasForAugment(final AugmentationTarget targetSchema, + final AugmentationSchemaNode augmentSchema) { + if (!targetSchema.getAvailableAugmentations().contains(augmentSchema)) { + return ImmutableSet.of(); } - - Set realChildNodes = Sets.newHashSet(); - - if(targetSchema instanceof DataNodeContainer) { - realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema); - } else if(targetSchema instanceof ChoiceSchemaNode) { - for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) targetSchema).getCases()) { - if(getChildNodesRecursive(choiceCaseNode).contains(dataSchemaNode.getQName())) { + if (targetSchema instanceof DataNodeContainer) { + return getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema); + } + final Set realChildNodes = new HashSet<>(); + if (targetSchema instanceof ChoiceSchemaNode) { + for (final DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) { + for (final CaseSchemaNode choiceCaseNode : ((ChoiceSchemaNode) targetSchema).getCases()) { + if (getChildNodesRecursive(choiceCaseNode).contains(dataSchemaNode.getQName())) { realChildNodes.add(choiceCaseNode.getDataChildByName(dataSchemaNode.getQName())); } } @@ -317,38 +331,39 @@ public final class SchemaUtils { } public static Set getRealSchemasForAugment(final DataNodeContainer targetSchema, - final AugmentationSchema augmentSchema) { - Set realChildNodes = Sets.newHashSet(); - for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) { - DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName()); + final AugmentationSchemaNode augmentSchema) { + final Set realChildNodes = new HashSet<>(); + for (final DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) { + final DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName()); realChildNodes.add(realChild); } return realChildNodes; } - public static Optional detectCase(final ChoiceSchemaNode schema, final DataContainerChild child) { - for (ChoiceCaseNode choiceCaseNode : schema.getCases()) { + public static Optional detectCase(final ChoiceSchemaNode schema, + final DataContainerChild child) { + for (final CaseSchemaNode choiceCaseNode : schema.getCases()) { if (child instanceof AugmentationNode - && belongsToCaseAugment(choiceCaseNode, - (YangInstanceIdentifier.AugmentationIdentifier) child.getIdentifier())) { + && belongsToCaseAugment(choiceCaseNode, (AugmentationIdentifier) child.getIdentifier())) { return Optional.of(choiceCaseNode); - } else if (choiceCaseNode.getDataChildByName(child.getNodeType()) != null) { + } else if (choiceCaseNode.findDataChildByName(child.getNodeType()).isPresent()) { return Optional.of(choiceCaseNode); } } - return Optional.absent(); + return Optional.empty(); } - public static boolean belongsToCaseAugment(final ChoiceCaseNode caseNode, final YangInstanceIdentifier.AugmentationIdentifier childToProcess) { - for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) { + public static boolean belongsToCaseAugment(final CaseSchemaNode caseNode, + final AugmentationIdentifier childToProcess) { + for (final AugmentationSchemaNode augmentationSchema : caseNode.getAvailableAugmentations()) { - Set currentAugmentChildNodes = Sets.newHashSet(); - for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) { + final Set currentAugmentChildNodes = new HashSet<>(); + for (final DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) { currentAugmentChildNodes.add(dataSchemaNode.getQName()); } - if(childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){ + if (childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)) { return true; } } @@ -356,17 +371,177 @@ public final class SchemaUtils { return false; } - public static YangInstanceIdentifier.AugmentationIdentifier getNodeIdentifierForAugmentation(final AugmentationSchema schema) { - return new YangInstanceIdentifier.AugmentationIdentifier(getChildQNames(schema)); + /** + * Tries to find in {@code parent} which is dealed as augmentation target node with QName as {@code child}. If such + * node is found then it is returned, else null. + * + * @param parent parent node + * @param child child node + * @return augmentation schema + */ + public static AugmentationSchemaNode findCorrespondingAugment(final DataSchemaNode parent, + final DataSchemaNode child) { + if (!(parent instanceof AugmentationTarget) || parent instanceof ChoiceSchemaNode) { + return null; + } + + for (final AugmentationSchemaNode augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) { + final Optional childInAugmentation = augmentation.findDataChildByName(child.getQName()); + if (childInAugmentation.isPresent()) { + return augmentation; + } + } + return null; + } + + /** + * Finds schema node for given path in schema context. This method performs + * lookup in the namespace of all leafs, leaf-lists, lists, containers, + * choices, rpcs, actions, notifications, anydatas, and anyxmls according to + * Rfc6050/Rfc7950 section 6.2.1. + * + * @param schemaContext + * schema context + * @param path + * path + * @return schema node on path + */ + public static SchemaNode findDataParentSchemaOnPath(final SchemaContext schemaContext, final SchemaPath path) { + SchemaNode current = requireNonNull(schemaContext); + for (final QName qname : path.getPathFromRoot()) { + current = findDataChildSchemaByQName(current, qname); + } + return current; } - public static Set getChildQNames(final AugmentationSchema schema) { - Set qnames = Sets.newHashSet(); + /** + * Find child data schema node identified by its QName within a provided schema node. This method performs lookup + * in the namespace of all leafs, leaf-lists, lists, containers, choices, rpcs, actions, notifications, anydatas + * and anyxmls according to RFC6050/RFC7950 section 6.2.1. + * + * @param node + * schema node + * @param qname + * QName + * @return data child schema node + * @throws IllegalArgumentException + * if the schema node does not allow children + */ + public static @Nullable SchemaNode findDataChildSchemaByQName(final SchemaNode node, final QName qname) { + if (node instanceof DataNodeContainer) { + SchemaNode child = ((DataNodeContainer) node).dataChildByName(qname); + if (child == null && node instanceof SchemaContext) { + child = tryFind(((SchemaContext) node).getOperations(), qname).orElse(null); + } + if (child == null && node instanceof NotificationNodeContainer) { + child = tryFind(((NotificationNodeContainer) node).getNotifications(), qname).orElse(null); + } + if (child == null && node instanceof ActionNodeContainer) { + child = tryFind(((ActionNodeContainer) node).getActions(), qname).orElse(null); + } - for (DataSchemaNode dataSchemaNode : schema.getChildNodes()) { - qnames.add(dataSchemaNode.getQName()); + return child; + } + if (node instanceof ChoiceSchemaNode) { + return ((ChoiceSchemaNode) node).findCase(qname).orElse(null); + } + if (node instanceof OperationDefinition) { + switch (qname.getLocalName()) { + case "input": + return ((OperationDefinition) node).getInput(); + case "output": + return ((OperationDefinition) node).getOutput(); + default: + return null; + } } - return qnames; + throw new IllegalArgumentException(String.format("Schema node %s does not allow children.", node)); + } + + /** + * Finds schema node for given path in schema context. This method performs lookup in both the namespace + * of groupings and the namespace of all leafs, leaf-lists, lists, containers, choices, rpcs, actions, + * notifications, anydatas and anyxmls according to Rfc6050/Rfc7950 section 6.2.1. + * + *

+ * This method returns collection of SchemaNodes, because name conflicts can occur between the namespace + * of groupings and namespace of data nodes. This method finds and collects all schema nodes that matches supplied + * SchemaPath and returns them all as collection of schema nodes. + * + * @param schemaContext + * schema context + * @param path + * path + * @return collection of schema nodes on path + */ + public static Collection findParentSchemaNodesOnPath(final SchemaContext schemaContext, + final SchemaPath path) { + return findParentSchemaNodesOnPath(schemaContext, path.getPathFromRoot()); + } + + /** + * Finds schema node for given path in schema context. This method performs lookup in both the namespace + * of groupings and the namespace of all leafs, leaf-lists, lists, containers, choices, rpcs, actions, + * notifications, anydatas and anyxmls according to Rfc6050/Rfc7950 section 6.2.1. + * + *

+ * This method returns collection of SchemaNodes, because name conflicts can occur between the namespace + * of groupings and namespace of data nodes. This method finds and collects all schema nodes that matches supplied + * SchemaPath and returns them all as collection of schema nodes. + * + * @param schemaContext schema context + * @param path path + * @return collection of schema nodes on path + */ + public static Collection findParentSchemaNodesOnPath(final SchemaContext schemaContext, + final Iterable path) { + final Collection currentNodes = new ArrayList<>(); + final Collection childNodes = new ArrayList<>(); + currentNodes.add(requireNonNull(schemaContext)); + for (final QName qname : path) { + for (final SchemaNode current : currentNodes) { + childNodes.addAll(findChildSchemaNodesByQName(current, qname)); + } + currentNodes.clear(); + currentNodes.addAll(childNodes); + childNodes.clear(); + } + + return currentNodes; + } + + /** + * Find child schema node identified by its QName within a provided schema node. This method performs lookup in both + * the namespace of groupings and the namespace of all leafs, leaf-lists, lists, containers, choices, rpcs, + * actions, notifications, anydatas and anyxmls according to RFC6050/RFC7950 section 6.2.1. + * + *

+ * This method returns collection of SchemaNodes, because name conflicts can occur between the namespace + * of groupings and namespace of data nodes. This method finds and collects all schema nodes with supplied QName + * and returns them all as collection of schema nodes. + * + * @param node + * schema node + * @param qname + * QName + * @return collection of child schema nodes + * @throws IllegalArgumentException + * if the schema node does not allow children + */ + public static Collection findChildSchemaNodesByQName(final SchemaNode node, final QName qname) { + final List childNodes = new ArrayList<>(); + final SchemaNode dataNode = findDataChildSchemaByQName(node, qname); + if (dataNode != null) { + childNodes.add(dataNode); + } + if (node instanceof DataNodeContainer) { + tryFind(((DataNodeContainer) node).getGroupings(), qname).ifPresent(childNodes::add); + } + return childNodes.isEmpty() ? ImmutableList.of() : ImmutableList.copyOf(childNodes); + } + + private static Optional tryFind(final Collection nodes, final QName qname) { + return nodes.stream().filter(node -> qname.equals(node.getQName())).findFirst(); } }