X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-model-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fmodel%2Futil%2FSchemaContextUtil.java;h=2d2240c38296cf2ee1783688f64358351b66e5e2;hb=1636eaae9a133d79301b7ebb02ae8d6a5fc38117;hp=accaec0da69abdff42b09263762728a3e8f8673d;hpb=2bf36e1205b58767daf67e9e532cbc95e9ea5a48;p=yangtools.git diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java index accaec0da6..2d2240c382 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java @@ -9,21 +9,21 @@ package org.opendaylight.yangtools.yang.model.util; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; -import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer; +import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; @@ -35,13 +35,18 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.ModuleImport; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; +import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer; +import org.opendaylight.yangtools.yang.model.api.OperationDefinition; import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; 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; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,17 +71,16 @@ public final class SchemaContextUtil { * the end of the SchemaPath. If the DataSchemaNode is not present in the * Schema Context the method will return null.
* In case that Schema Context or Schema Path are not specified correctly - * (i.e. contains null values) the method will return + * (i.e. contains null values) the method will throw * IllegalArgumentException. * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param schemaPath * Schema Path to search for * @return SchemaNode from the end of the Schema Path or null * if the Node is not present. + * @throws IllegalArgumentException if context or schemaPath is not correct. */ public static SchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) { Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); @@ -110,8 +114,6 @@ public final class SchemaContextUtil { * method will return specified Data Schema Node, otherwise the operation * will fail and method will return null. * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param module @@ -122,19 +124,35 @@ public final class SchemaContextUtil { * Non-conditional Revision Aware XPath, or null if the * DataSchemaNode is not present in Schema Context. */ - public static SchemaNode findDataSchemaNode(final SchemaContext context, final Module module, final RevisionAwareXPath nonCondXPath) { + // FIXME: This entire method is ill-defined, as the resolution process depends on where the XPath is defined -- + // notably RPCs, actions and notifications modify the data tree temporarily. See sections 6.4.1 and 9.9.2 + // of RFC7950. + // + // Most notably we need to understand whether the XPath is being resolved in the data tree, or as part of + // a notification/action/RPC, as then the SchemaContext grows tentative nodes ... which could be addressed + // via a derived SchemaContext (i.e. this class would have to have a + // + // SchemaContext notificationSchemaContext(SchemaContext delegate, NotificationDefinition notif) + // + // which would then be passed in to a method similar to this one. In static contexts, like MD-SAL codegen, + // that feels like an overkill. + public static SchemaNode findDataSchemaNode(final SchemaContext context, final Module module, + final RevisionAwareXPath nonCondXPath) { Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(module != null, "Module reference cannot be NULL"); Preconditions.checkArgument(nonCondXPath != null, "Non Conditional Revision Aware XPath cannot be NULL"); final String strXPath = nonCondXPath.toString(); if (strXPath != null) { - Preconditions.checkArgument(strXPath.indexOf('[') == -1, "Revision Aware XPath may not contain a condition"); + Preconditions.checkArgument(strXPath.indexOf('[') == -1, + "Revision Aware XPath may not contain a condition"); if (nonCondXPath.isAbsolute()) { - final List qnamedPath = xpathToQNamePath(context, module, strXPath); - if (qnamedPath != null) { - return findNodeInSchemaContext(context, qnamedPath); - } + final List path = xpathToQNamePath(context, module, strXPath); + + // We do not have enough information about resolution context, hence cannot account for actions, RPCs + // and notifications. We therefore attempt to make a best estimate, but this can still fail. + final Optional pureData = context.findDataTreeChild(path); + return pureData.isPresent() ? pureData.get() : findNodeInSchemaContext(context, path); } } return null; @@ -165,8 +183,6 @@ public final class SchemaContextUtil { * the method will return specified Data Schema Node, otherwise the * operation will fail and method will return null. * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param module @@ -179,6 +195,18 @@ public final class SchemaContextUtil { * given relative Revision Aware XPath, otherwise will return * null. */ + // FIXME: This entire method is ill-defined, as the resolution process depends on where the XPath is defined -- + // notably RPCs, actions and notifications modify the data tree temporarily. See sections 6.4.1 and 9.9.2 + // of RFC7950. + // + // Most notably we need to understand whether the XPath is being resolved in the data tree, or as part of + // a notification/action/RPC, as then the SchemaContext grows tentative nodes ... which could be addressed + // via a derived SchemaContext (i.e. this class would have to have a + // + // SchemaContext notificationSchemaContext(SchemaContext delegate, NotificationDefinition notif) + // + // which would then be passed in to a method similar to this one. In static contexts, like MD-SAL codegen, + // that feels like an overkill. public static SchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module, final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) { Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); @@ -193,9 +221,10 @@ public final class SchemaContextUtil { if (actualNodePath != null) { final Iterable qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode); - if (qnamePath != null) { - return findNodeInSchemaContext(context, qnamePath); - } + // We do not have enough information about resolution context, hence cannot account for actions, RPCs + // and notifications. We therefore attempt to make a best estimate, but this can still fail. + final Optional pureData = context.findDataTreeChild(qnamePath); + return pureData.isPresent() ? pureData.get() : findNodeInSchemaContext(context, qnamePath); } return null; } @@ -207,15 +236,12 @@ public final class SchemaContextUtil { * If Schema Context or Schema Node contains null references * the method will throw IllegalArgumentException * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param schemaNode * Schema Node - * @return Yang Module for specified Schema Context and Schema Node, if - * Schema Node is NOT present, the method will returns - * null + * @return Yang Module for specified Schema Context and Schema Node, if Schema Node is NOT present, the method will + * return null */ public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) { Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL!"); @@ -224,39 +250,40 @@ public final class SchemaContextUtil { + "set properly (Schema Path is NULL)"); final QName qname = schemaNode.getPath().getLastComponent(); - Preconditions.checkState(qname != null, - "Schema Path contains invalid state of path parts. " + - "The Schema Path MUST contain at least ONE QName which defines namespace and Local name of path."); - return context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision()); + Preconditions.checkState(qname != null, "Schema Path contains invalid state of path parts. " + + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name of path."); + return context.findModule(qname.getModule()).orElse(null); } public static SchemaNode findNodeInSchemaContext(final SchemaContext context, final Iterable path) { final QName current = path.iterator().next(); LOG.trace("Looking up module {} in context {}", current, path); - final Module module = context.findModuleByNamespaceAndRevision(current.getNamespace(), current.getRevision()); - if (module == null) { + final Optional module = context.findModule(current.getModule()); + if (!module.isPresent()) { LOG.debug("Module {} not found", current); return null; } - return findNodeInModule(module, path); + return findNodeInModule(module.get(), path); } /** - * Returns NotificationDefinition from Schema Context + * Returns NotificationDefinition from Schema Context. * * @param schema SchemaContext in which lookup should be performed. * @param path Schema Path of notification * @return Notification schema or null, if notification is not present in schema context. */ @Beta - @Nullable public static NotificationDefinition getNotificationSchema(@Nonnull final SchemaContext schema, @Nonnull final SchemaPath path) { + @Nullable + public static NotificationDefinition getNotificationSchema(@Nonnull final SchemaContext schema, + @Nonnull final SchemaPath path) { Preconditions.checkNotNull(schema, "Schema context must not be null."); Preconditions.checkNotNull(path, "Schema path must not be null."); for (final NotificationDefinition potential : schema.getNotifications()) { if (path.equals(potential.getPath())) { - return potential; + return potential; } } return null; @@ -270,7 +297,9 @@ public final class SchemaContextUtil { * @return Notification schema or null, if notification is not present in schema context. */ @Beta - @Nullable public static ContainerSchemaNode getRpcDataSchema(@Nonnull final SchemaContext schema, @Nonnull final SchemaPath path) { + @Nullable + public static ContainerSchemaNode getRpcDataSchema(@Nonnull final SchemaContext schema, + @Nonnull final SchemaPath path) { Preconditions.checkNotNull(schema, "Schema context must not be null."); Preconditions.checkNotNull(path, "Schema path must not be null."); final Iterator it = path.getPathFromRoot().iterator(); @@ -280,12 +309,36 @@ public final class SchemaContextUtil { final QName inOrOut = it.next(); for (final RpcDefinition potential : schema.getOperations()) { if (rpcName.equals(potential.getQName())) { - return SchemaNodeUtils.getRpcDataSchema(potential, inOrOut); + return SchemaNodeUtils.getRpcDataSchema(potential, inOrOut); } } return null; } + /** + * Extract the identifiers of all modules and submodules which were used to create a particular SchemaContext. + * + * @param context SchemaContext to be examined + * @return Set of ModuleIdentifiers. + */ + public static Set getConstituentModuleIdentifiers(final SchemaContext context) { + final Set ret = new HashSet<>(); + + for (Module module : context.getModules()) { + ret.add(moduleToIdentifier(module)); + + for (Module submodule : module.getSubmodules()) { + ret.add(moduleToIdentifier(submodule)); + } + } + + return ret; + } + + private static SourceIdentifier moduleToIdentifier(final Module module) { + return RevisionSourceIdentifier.create(module.getName(), module.getRevision()); + } + private static SchemaNode findNodeInModule(final Module module, final Iterable path) { Preconditions.checkArgument(module != null, "Parent reference cannot be NULL"); @@ -368,8 +421,24 @@ public final class SchemaContextUtil { } } - if (foundNode == null && parent instanceof RpcDefinition) { - final RpcDefinition parentRpcDefinition = (RpcDefinition) parent; + if (foundNode == null && parent instanceof ActionNodeContainer) { + foundNode = ((ActionNodeContainer) parent).getActions().stream() + .filter(act -> current.equals(act.getQName())).findFirst().orElse(null); + if (foundNode != null && nextPath.iterator().hasNext()) { + foundNode = findNodeIn(foundNode, nextPath); + } + } + + if (foundNode == null && parent instanceof NotificationNodeContainer) { + foundNode = ((NotificationNodeContainer) parent).getNotifications().stream() + .filter(notif -> current.equals(notif.getQName())).findFirst().orElse(null); + if (foundNode != null && nextPath.iterator().hasNext()) { + foundNode = findNodeIn(foundNode, nextPath); + } + } + + if (foundNode == null && parent instanceof OperationDefinition) { + final OperationDefinition parentRpcDefinition = (OperationDefinition) parent; if (current.getLocalName().equals("input")) { foundNode = parentRpcDefinition.getInput(); @@ -395,9 +464,21 @@ public final class SchemaContextUtil { if (foundNode == null && parent instanceof ChoiceSchemaNode) { foundNode = ((ChoiceSchemaNode) parent).getCaseNodeByName(current); + if (foundNode != null && nextPath.iterator().hasNext()) { foundNode = findNodeIn(foundNode, nextPath); } + + if (foundNode == null) { + // fallback that tries to map into one of the child cases + for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) parent).getCases().values()) { + final DataSchemaNode maybeChild = caseNode.getDataChildByName(current); + if (maybeChild != null) { + foundNode = findNodeIn(maybeChild, nextPath); + break; + } + } + } } if (foundNode == null) { @@ -439,7 +520,7 @@ public final class SchemaContextUtil { return null; } - private static GroupingDefinition getGroupingByName(final RpcDefinition rpc, final QName name) { + private static GroupingDefinition getGroupingByName(final OperationDefinition rpc, final QName name) { for (final GroupingDefinition grouping : rpc.getGroupings()) { if (grouping.getQName().equals(name)) { return grouping; @@ -455,8 +536,6 @@ public final class SchemaContextUtil { * If Schema Context, Parent Module or XPath string contains * null values, the method will throws IllegalArgumentException * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param parentModule @@ -464,13 +543,18 @@ public final class SchemaContextUtil { * @param xpath * XPath String * @return return a list of QName + * + * @throws IllegalArgumentException if any arguments are null + * */ - private static List xpathToQNamePath(final SchemaContext context, final Module parentModule, final String xpath) { + private static List xpathToQNamePath(final SchemaContext context, final Module parentModule, + final String xpath) { + // FIXME: 2.0.0: this should throw NPE, not IAE Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL"); Preconditions.checkArgument(xpath != null, "XPath string reference cannot be NULL"); - final List path = new LinkedList(); + final List path = new LinkedList<>(); for (final String pathComponent : SLASH_SPLITTER.split(xpath)) { if (!pathComponent.isEmpty()) { path.add(stringPathPartToQName(context, parentModule, pathComponent)); @@ -490,8 +574,6 @@ public final class SchemaContextUtil { * If Schema Context, Parent Module or Prefixed Path Part refers to * null the method will throw IllegalArgumentException * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param parentModule @@ -499,8 +581,11 @@ public final class SchemaContextUtil { * @param prefixedPathPart * Prefixed Path Part string * @return QName from prefixed Path Part String. + * @throws IllegalArgumentException if any arguments are null */ - private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, final String prefixedPathPart) { + private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, + final String prefixedPathPart) { + // FIXME: 2.0.0: this should throw NPE, not IAE Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL"); Preconditions.checkArgument(prefixedPathPart != null, "Prefixed Path Part cannot be NULL!"); @@ -510,13 +595,14 @@ public final class SchemaContextUtil { final String modulePrefix = prefixedName.next(); final Module module = resolveModuleForPrefix(context, parentModule, modulePrefix); - Preconditions.checkArgument(module != null, "Failed to resolve xpath: no module found for prefix %s in module %s", - modulePrefix, parentModule.getName()); + Preconditions.checkArgument(module != null, + "Failed to resolve xpath: no module found for prefix %s in module %s", modulePrefix, + parentModule.getName()); return QName.create(module.getQNameModule(), prefixedName.next()); - } else { - return QName.create(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } + + return QName.create(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } /** @@ -532,8 +618,6 @@ public final class SchemaContextUtil { * If Schema Context, Module or Prefix are referring to null * the method will return IllegalArgumentException * - * @throws IllegalArgumentException - * * @param context * Schema Context * @param module @@ -542,8 +626,11 @@ public final class SchemaContextUtil { * Module Prefix * @return Module for given prefix in specified Schema Context if is * present, otherwise returns null + * @throws IllegalArgumentException if any arguments are null */ - private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) { + private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, + final String prefix) { + // FIXME: 2.0.0: this should throw NPE, not IAE Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(module != null, "Module reference cannot be NULL"); Preconditions.checkArgument(prefix != null, "Prefix string cannot be NULL"); @@ -555,14 +642,14 @@ public final class SchemaContextUtil { final Set imports = module.getImports(); for (final ModuleImport mi : imports) { if (prefix.equals(mi.getPrefix())) { - return context.findModuleByName(mi.getModuleName(), mi.getRevision()); + return context.findModule(mi.getModuleName(), mi.getRevision()).orElse(null); } } return null; } /** - * @throws IllegalArgumentException + * Resolve a relative XPath into a set of QNames. * * @param context * Schema Context @@ -573,9 +660,11 @@ public final class SchemaContextUtil { * @param actualSchemaNode * actual schema node * @return list of QName + * @throws IllegalArgumentException if any arguments are null */ private static Iterable resolveRelativeXPath(final SchemaContext context, final Module module, final RevisionAwareXPath relativeXPath, final SchemaNode actualSchemaNode) { + // FIXME: 2.0.0: this should throw NPE, not IAE Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(module != null, "Module reference cannot be NULL"); Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL"); @@ -599,25 +688,17 @@ public final class SchemaContextUtil { if (Iterables.size(schemaNodePath) - colCount >= 0) { return Iterables.concat(Iterables.limit(schemaNodePath, Iterables.size(schemaNodePath) - colCount), - Iterables.transform(Iterables.skip(xpaths, colCount), new Function() { - @Override - public QName apply(final String input) { - return stringPathPartToQName(context, module, input); - } - })); + Iterables.transform(Iterables.skip(xpaths, colCount), + input -> stringPathPartToQName(context, module, input))); } return Iterables.concat(schemaNodePath, - Iterables.transform(Iterables.skip(xpaths, colCount), new Function() { - @Override - public QName apply(final String input) { - return stringPathPartToQName(context, module, input); - } - })); + Iterables.transform(Iterables.skip(xpaths, colCount), + input -> stringPathPartToQName(context, module, input))); } /** - * Extracts the base type of node on which schema node points to. If target node is again of type LeafrefTypeDefinition, methods will be call recursively until it reach concrete - * type definition. + * Extracts the base type of node on which schema node points to. If target node is again of type + * LeafrefTypeDefinition, methods will be call recursively until it reach concrete type definition. * * @param typeDefinition * type of node which will be extracted @@ -625,156 +706,99 @@ public final class SchemaContextUtil { * Schema Context * @param schema * Schema Node - * @return recursively found type definition this leafref is pointing to or null if the xpath is incorrect (null is there to preserve backwards compatibility) + * @return recursively found type definition this leafref is pointing to or null if the xpath is incorrect (null + * is there to preserve backwards compatibility) */ - public static TypeDefinition getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition, final SchemaContext schemaContext, final SchemaNode schema) { + public static TypeDefinition getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition, + final SchemaContext schemaContext, final SchemaNode schema) { RevisionAwareXPath pathStatement = typeDefinition.getPathStatement(); - pathStatement = new RevisionAwareXPathImpl(stripConditionsFromXPathString(pathStatement), pathStatement.isAbsolute()); - - SchemaNode baseSchema = schema; - while (baseSchema instanceof DerivableSchemaNode) { - final Optional basePotential = ((DerivableSchemaNode) baseSchema).getOriginal(); - if (basePotential.isPresent()) { - baseSchema = basePotential.get(); - } else { - break; - } - } - - Module parentModule = findParentModuleOfReferencingType(schemaContext, baseSchema); + pathStatement = new RevisionAwareXPathImpl(stripConditionsFromXPathString(pathStatement), + pathStatement.isAbsolute()); final DataSchemaNode dataSchemaNode; - if(pathStatement.isAbsolute()) { - dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, pathStatement); + if (pathStatement.isAbsolute()) { + SchemaNode baseSchema = schema; + while (baseSchema instanceof DerivableSchemaNode) { + final Optional basePotential = ((DerivableSchemaNode) baseSchema).getOriginal(); + if (basePotential.isPresent()) { + baseSchema = basePotential.get(); + } else { + break; + } + } + + Module parentModule = findParentModuleOfReferencingType(schemaContext, baseSchema); + dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, + pathStatement); } else { - dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule, baseSchema, pathStatement); + Module parentModule = findParentModule(schemaContext, schema); + dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, + parentModule, schema, pathStatement); } // FIXME this is just to preserve backwards compatibility since yangtools do not mind wrong leafref xpaths // and current expected behaviour for such cases is to just use pure string // This should throw an exception about incorrect XPath in leafref - if(dataSchemaNode == null) { + if (dataSchemaNode == null) { return null; } final TypeDefinition targetTypeDefinition = typeDefinition(dataSchemaNode); - if(targetTypeDefinition instanceof LeafrefTypeDefinition) { - return getBaseTypeForLeafRef(((LeafrefTypeDefinition) targetTypeDefinition), schemaContext, dataSchemaNode); - } else { - return targetTypeDefinition; + if (targetTypeDefinition instanceof LeafrefTypeDefinition) { + return getBaseTypeForLeafRef((LeafrefTypeDefinition) targetTypeDefinition, schemaContext, dataSchemaNode); } - } - private static Module findParentModuleOfReferencingType(final SchemaContext schemaContext, - final SchemaNode schemaNode) { - Preconditions.checkArgument(schemaContext != null, "Schema Context reference cannot be NULL!"); - Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!"); - TypeDefinition nodeType = null; + return targetTypeDefinition; + } - if (schemaNode instanceof LeafSchemaNode) { - nodeType = ((LeafSchemaNode) schemaNode).getType(); - } else if (schemaNode instanceof LeafListSchemaNode) { - nodeType = ((LeafListSchemaNode) schemaNode).getType(); + /** + * Returns base type for {@code typeDefinition} which belongs to module specified via {@code qname}. This handle + * the case when leafref type isn't specified as type substatement of leaf or leaf-list but is defined in other + * module as typedef which is then imported to referenced module. + * + *

+ * Because {@code typeDefinition} is definied via typedef statement, only absolute path is meaningful. + */ + public static TypeDefinition getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition, + final SchemaContext schemaContext, final QName qname) { + final RevisionAwareXPath pathStatement = typeDefinition.getPathStatement(); + final RevisionAwareXPath strippedPathStatement = new RevisionAwareXPathImpl( + stripConditionsFromXPathString(pathStatement), pathStatement.isAbsolute()); + if (!strippedPathStatement.isAbsolute()) { + return null; } - if (nodeType instanceof ExtendedType) { - while (nodeType.getBaseType() instanceof ExtendedType) { - nodeType = nodeType.getBaseType(); - } - - QNameModule typeDefModuleQname = nodeType.getQName().getModule(); - return schemaContext.findModuleByNamespaceAndRevision(typeDefModuleQname.getNamespace(), - typeDefModuleQname.getRevision()); - } else if (nodeType.getBaseType() != null) { - while (nodeType.getBaseType() != null) { - nodeType = nodeType.getBaseType(); - } + final Optional parentModule = schemaContext.findModule(qname.getModule()); + Preconditions.checkArgument(parentModule.isPresent(), "Failed to find parent module for %s", qname); - final QNameModule typeDefModuleQname = nodeType.getQName().getModule(); - return schemaContext.findModuleByNamespaceAndRevision(typeDefModuleQname.getNamespace(), - typeDefModuleQname.getRevision()); + final DataSchemaNode dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNode(schemaContext, + parentModule.get(), strippedPathStatement); + final TypeDefinition targetTypeDefinition = typeDefinition(dataSchemaNode); + if (targetTypeDefinition instanceof LeafrefTypeDefinition) { + return getBaseTypeForLeafRef((LeafrefTypeDefinition) targetTypeDefinition, schemaContext, dataSchemaNode); } - return SchemaContextUtil.findParentModule(schemaContext, schemaNode); + return targetTypeDefinition; } - /** - * @deprecated due to expensive lookup - * Returns parent Yang Module for specified Schema Context in which Schema - * Node is declared. If Schema Node is of type 'ExtendedType' it tries to find parent module - * in which the type was originally declared (needed for correct leafref path resolution).
- * If the Schema Node is not present in Schema Context the - * operation will return null.
- * If Schema Context or Schema Node contains null references - * the method will throw IllegalArgumentException - * - * @throws IllegalArgumentException - * - * @param schemaContext - * Schema Context - * @param schemaNode - * Schema Node - * @return Yang Module for specified Schema Context and Schema Node, if - * Schema Node is NOT present, the method will returns - * null - */ - @Deprecated - public static Module findParentModuleByType(final SchemaContext schemaContext, final SchemaNode schemaNode) { + private static Module findParentModuleOfReferencingType(final SchemaContext schemaContext, + final SchemaNode schemaNode) { Preconditions.checkArgument(schemaContext != null, "Schema Context reference cannot be NULL!"); - Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!"); - TypeDefinition nodeType = null; + Preconditions.checkArgument(schemaNode instanceof TypedDataSchemaNode, "Unsupported node %s", schemaNode); - if (schemaNode instanceof LeafSchemaNode) { - nodeType = ((LeafSchemaNode) schemaNode).getType(); - } else if (schemaNode instanceof LeafListSchemaNode) { - nodeType = ((LeafListSchemaNode) schemaNode).getType(); - } - - if (!BaseTypes.isYangBuildInType(nodeType) && nodeType.getBaseType() != null) { - while (nodeType.getBaseType() != null && !BaseTypes.isYangBuildInType(nodeType.getBaseType())) { + TypeDefinition nodeType = ((TypedDataSchemaNode) schemaNode).getType(); + if (nodeType.getBaseType() != null) { + while (nodeType.getBaseType() != null) { nodeType = nodeType.getBaseType(); } - QNameModule typeDefModuleQname = nodeType.getQName().getModule(); - - return schemaContext.findModuleByNamespaceAndRevision(typeDefModuleQname.getNamespace(), - typeDefModuleQname.getRevision()); + return schemaContext.findModule(nodeType.getQName().getModule()).orElse(null); } return SchemaContextUtil.findParentModule(schemaContext, schemaNode); } - /** - * Returns base type for {@code typeDefinition} which belongs to module specified via {@code qName}. This handle case - * when leafref type isn't specified as type substatement of leaf or leaf-list but is defined in other module as typedef - * which is then imported to referenced module. - * - * Because {@code typeDefinition} is definied via typedef statement, only absolute path is meaningful. - * - * @param typeDefinition - * @param schemaContext - * @param qName - * @return - */ - public static TypeDefinition getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition, - final SchemaContext schemaContext, final QName qName) { - final RevisionAwareXPath pathStatement = typeDefinition.getPathStatement(); - final RevisionAwareXPath strippedPathStatement = new RevisionAwareXPathImpl(stripConditionsFromXPathString(pathStatement), pathStatement.isAbsolute()); - if (!strippedPathStatement.isAbsolute()) { - return null; - } - - final Module parentModule = schemaContext.findModuleByNamespaceAndRevision(qName.getNamespace(),qName.getRevision()); - final DataSchemaNode dataSchemaNode = (DataSchemaNode) SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, strippedPathStatement); - final TypeDefinition targetTypeDefinition = typeDefinition(dataSchemaNode); - if (targetTypeDefinition instanceof LeafrefTypeDefinition) { - return getBaseTypeForLeafRef(((LeafrefTypeDefinition) targetTypeDefinition), schemaContext, dataSchemaNode); - } else { - return targetTypeDefinition; - } - } - private static final Pattern STRIP_PATTERN = Pattern.compile("\\[[^\\[\\]]*\\]"); /** @@ -783,7 +807,6 @@ public final class SchemaContextUtil { * @param pathStatement * xPath to target node * @return string representation of xPath without conditions - * */ @VisibleForTesting static String stripConditionsFromXPathString(final RevisionAwareXPath pathStatement) { @@ -797,7 +820,7 @@ public final class SchemaContextUtil { * a node representing LeafSchemaNode * @return concrete type definition of node value */ - private static TypeDefinition typeDefinition(final LeafSchemaNode node) { + private static TypeDefinition typeDefinition(final LeafSchemaNode node) { TypeDefinition baseType = node.getType(); while (baseType.getBaseType() != null) { baseType = baseType.getBaseType(); @@ -812,7 +835,7 @@ public final class SchemaContextUtil { * a node representing LeafListSchemaNode * @return concrete type definition of node value */ - private static TypeDefinition typeDefinition(final LeafListSchemaNode node) { + private static TypeDefinition typeDefinition(final LeafListSchemaNode node) { TypeDefinition baseType = node.getType(); while (baseType.getBaseType() != null) { baseType = baseType.getBaseType(); @@ -827,13 +850,13 @@ public final class SchemaContextUtil { * a node representing DataSchemaNode * @return concrete type definition of node value */ - private static TypeDefinition typeDefinition(final DataSchemaNode node) { + private static TypeDefinition typeDefinition(final DataSchemaNode node) { if (node instanceof LeafListSchemaNode) { return typeDefinition((LeafListSchemaNode) node); } else if (node instanceof LeafSchemaNode) { return typeDefinition((LeafSchemaNode) node); } else { - throw new IllegalArgumentException("Unhandled parameter types: " + Arrays. asList(node).toString()); + throw new IllegalArgumentException("Unhandled parameter type: " + node); } } }