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=84f7284aeeb23860788f4fe87fb357d890a7ce01;hb=81f9e1b49eb5c7f5068a6f070d47c734884d756b;hp=84ad453df877a9f7226d8a2e6f218b01c3e7207c;hpb=8eb7b8f1ac5307b0cba19468fed2af43894c00ed;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 84ad453df8..84f7284aee 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,53 +7,107 @@ */ 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 com.google.common.base.Predicate; import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; -import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +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.RpcDefinition; +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 static final Function QNAME_FUNCTION = new Function() { + @Override + public QName apply(@Nonnull final DataSchemaNode input) { + return input.getQName(); + } + }; + private SchemaUtils() { + throw new UnsupportedOperationException(); } - public static final Optional findFirstSchema(final QName qname, final Iterable dataSchemaNode) { + /** + * @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 Optional findFirstSchema(final QName qname, final Iterable dataSchemaNode) { + DataSchemaNode sNode = null; if (dataSchemaNode != null && qname != null) { for (DataSchemaNode dsn : dataSchemaNode) { if (qname.isEqualWithoutRevision(dsn.getQName())) { - return Optional. of(dsn); - } else if (dsn instanceof ChoiceNode) { - for (ChoiceCaseNode choiceCase : ((ChoiceNode) dsn).getCases()) { + if (sNode == null || sNode.getQName().getRevision().compareTo(dsn.getQName().getRevision()) < 0) { + sNode = 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); + } Optional foundDsn = findFirstSchema(qname, choiceCase.getChildNodes()); - if (foundDsn != null && foundDsn.isPresent()) { + if (foundDsn.isPresent()) { return foundDsn; } } } } } - return Optional.absent(); + return Optional.fromNullable(sNode); } + /** + * + * 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 + * @return found schema node + * @throws java.lang.IllegalStateException if the child was not found in parent schema node + */ public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname) { - return findSchemaForChild(schema, qname, schema.getChildNodes()); + // 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; + } + + @Nullable + public static DataSchemaNode findSchemaForChild(final DataNodeContainer schema, final QName qname, final boolean strictMode) { + if (strictMode) { + return findSchemaForChild(schema, qname); + } + + 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) { @@ -70,12 +124,12 @@ public final class SchemaUtils { return schemaForAugment.get(); } - public static AugmentationSchema findSchemaForAugment(final ChoiceNode schema, final Set qNames) { + 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()) { + if (schemaForAugment.isPresent()) { break; } } @@ -90,12 +144,13 @@ public final class SchemaUtils { HashSet qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function() { @Override - public QName apply(final DataSchemaNode input) { + public QName apply(@Nonnull final DataSchemaNode input) { + Preconditions.checkNotNull(input); return input.getQName(); } })); - if(qNamesFromAugment.equals(qNames)) { + if (qNamesFromAugment.equals(qNames)) { return Optional.of(augment); } } @@ -103,7 +158,7 @@ public final class SchemaUtils { return Optional.absent(); } - public static DataSchemaNode findSchemaForChild(final ChoiceNode schema, final QName childPartialQName) { + public static DataSchemaNode findSchemaForChild(final ChoiceSchemaNode schema, final QName childPartialQName) { for (ChoiceCaseNode choiceCaseNode : schema.getCases()) { Optional childSchema = findFirstSchema(childPartialQName, choiceCaseNode.getChildNodes()); if (childSchema.isPresent()) { @@ -119,26 +174,27 @@ public final class SchemaUtils { /** * 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) { + 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) { + Map mappedChoices = Maps.newLinkedHashMap(); for (final DataSchemaNode childSchema : childNodes) { - if(childSchema instanceof ChoiceNode) { + if (childSchema instanceof ChoiceSchemaNode) { - if(isFromAugment(schema, childSchema)) { + if (isFromAugment(schema, childSchema)) { continue; } - for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) { + for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { for (QName qName : getChildNodesRecursive(choiceCaseNode)) { - mappedChoices.put(qName, (ChoiceNode) childSchema); + mappedChoices.put(qName, (ChoiceSchemaNode) childSchema); } } } @@ -153,7 +209,7 @@ public final class SchemaUtils { } for (AugmentationSchema augmentationSchema : ((AugmentationTarget) schema).getAvailableAugmentations()) { - if(augmentationSchema.getDataChildByName(childSchema.getQName()) != null) { + if (augmentationSchema.getDataChildByName(childSchema.getQName()) != null) { return true; } } @@ -164,6 +220,7 @@ 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) { @@ -195,8 +252,8 @@ public final class SchemaUtils { for (QName qName : getChildNodesRecursive((DataNodeContainer) child)) { childNodesToAugmentation.put(qName, mostTopAugmentation); } - } else if (child instanceof ChoiceNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) child).getCases()) { + } else if (child instanceof ChoiceSchemaNode) { + for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) child).getCases()) { for (QName qName : getChildNodesRecursive(choiceCaseNode)) { childNodesToAugmentation.put(qName, mostTopAugmentation); } @@ -208,8 +265,8 @@ public final class SchemaUtils { } // Choice Node has to map child nodes from all its cases - if (schema instanceof ChoiceNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) schema).getCases()) { + if (schema instanceof ChoiceSchemaNode) { + for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) schema).getCases()) { if (!(augments.containsKey(choiceCaseNode.getQName()))) { continue; } @@ -227,16 +284,19 @@ public final class SchemaUtils { * Recursively list all child nodes. * * 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(); for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) { - if(childSchema instanceof ChoiceNode) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) { + if (childSchema instanceof ChoiceSchemaNode) { + for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) childSchema).getCases()) { allChildNodes.addAll(getChildNodesRecursive(choiceCaseNode)); } - } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) { + } else if (childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) { allChildNodes.addAll(getChildNodesRecursive((DataNodeContainer) childSchema)); } else { @@ -251,8 +311,11 @@ 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. + * 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))) { @@ -261,12 +324,12 @@ public final class SchemaUtils { Set realChildNodes = Sets.newHashSet(); - if(targetSchema instanceof DataNodeContainer) { + if (targetSchema instanceof DataNodeContainer) { realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema); - } else if(targetSchema instanceof ChoiceNode) { + } else if (targetSchema instanceof ChoiceSchemaNode) { for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) { - for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) targetSchema).getCases()) { - if(getChildNodesRecursive(choiceCaseNode).contains(dataSchemaNode.getQName())) { + for (ChoiceCaseNode choiceCaseNode : ((ChoiceSchemaNode) targetSchema).getCases()) { + if (getChildNodesRecursive(choiceCaseNode).contains(dataSchemaNode.getQName())) { realChildNodes.add(choiceCaseNode.getDataChildByName(dataSchemaNode.getQName())); } } @@ -286,11 +349,10 @@ public final class SchemaUtils { return realChildNodes; } - public static Optional detectCase(final ChoiceNode schema, final DataContainerChild child) { + public static Optional detectCase(final ChoiceSchemaNode schema, final DataContainerChild child) { for (ChoiceCaseNode 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) { return Optional.of(choiceCaseNode); @@ -300,7 +362,7 @@ public final class SchemaUtils { return Optional.absent(); } - public static boolean belongsToCaseAugment(final ChoiceCaseNode caseNode, final YangInstanceIdentifier.AugmentationIdentifier childToProcess) { + public static boolean belongsToCaseAugment(final ChoiceCaseNode caseNode, final AugmentationIdentifier childToProcess) { for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) { Set currentAugmentChildNodes = Sets.newHashSet(); @@ -308,7 +370,7 @@ public final class SchemaUtils { currentAugmentChildNodes.add(dataSchemaNode.getQName()); } - if(childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){ + if (childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){ return true; } } @@ -316,17 +378,110 @@ 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 AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) { + if (parent instanceof AugmentationTarget && !(parent instanceof ChoiceSchemaNode)) { + for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) { + DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName()); + if (childInAugmentation != null) { + return augmentation; + } + } + } + return null; + } + + public static AugmentationIdentifier getNodeIdentifierForAugmentation(final AugmentationSchema schema) { + final Collection qnames = Collections2.transform(schema.getChildNodes(), QNAME_FUNCTION); + return new AugmentationIdentifier(ImmutableSet.copyOf(qnames)); + } + + /** + * Finds schema node for given path in schema context. + * @param schemaContext schema context + * @param path path + * @return schema node on path + */ + public static SchemaNode findParentSchemaOnPath(final SchemaContext schemaContext, final SchemaPath path) { + SchemaNode current = Preconditions.checkNotNull(schemaContext); + for (final QName qname : path.getPathFromRoot()) { + current = findChildSchemaByQName(current, qname); + } + return current; + } + + /** + * Find child schema node identified by its QName within a provided schema node. + * @param node schema node + * @param qname QName + * @return child schema node + * @throws java.lang.IllegalArgumentException if the schema node does not allow children + */ + public static SchemaNode findChildSchemaByQName(final SchemaNode node, final QName qname) { + SchemaNode child = null; + + if (node instanceof DataNodeContainer) { + child = ((DataNodeContainer) node).getDataChildByName(qname); + + if (child == null && node instanceof SchemaContext) { + child = tryFindGroupings((SchemaContext) node, qname).orNull(); + } + + if (child == null && node instanceof SchemaContext) { + child = tryFindNotification((SchemaContext) node, qname) + .or(tryFindRpc(((SchemaContext) node), qname)).orNull(); + } + } else if (node instanceof ChoiceSchemaNode) { + child = ((ChoiceSchemaNode) node).getCaseNodeByName(qname); + } else if (node instanceof RpcDefinition) { + switch (qname.getLocalName()) { + case "input": + child = ((RpcDefinition) node).getInput(); + break; + case "output": + child = ((RpcDefinition) node).getOutput(); + break; + default: + child = null; + break; + } + } else { + throw new IllegalArgumentException(String.format("Schema node %s does not allow children.", node)); + } + + return child; + } + + private static Optional tryFindGroupings(final SchemaContext ctx, final QName qname) { + return Optional.fromNullable(Iterables.find(ctx.getGroupings(), new SchemaNodePredicate(qname), null)); } - public static Set getChildQNames(final AugmentationSchema schema) { - Set qnames = Sets.newHashSet(); + private static Optional tryFindRpc(final SchemaContext ctx, final QName qname) { + return Optional.fromNullable(Iterables.find(ctx.getOperations(), new SchemaNodePredicate(qname), null)); + } + + private static Optional tryFindNotification(final SchemaContext ctx, final QName qname) { + return Optional.fromNullable(Iterables.find(ctx.getNotifications(), new SchemaNodePredicate(qname), null)); + } - for (DataSchemaNode dataSchemaNode : schema.getChildNodes()) { - qnames.add(dataSchemaNode.getQName()); + private static final class SchemaNodePredicate implements Predicate { + private final QName qname; + + public SchemaNodePredicate(final QName qname) { + this.qname = qname; } - return qnames; + @Override + public boolean apply(final SchemaNode input) { + return input.getQName().equals(qname); + } } + }