X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fsal%2Fyang-prototype%2Fyang%2Fyang-model-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fyang%2Fmodel%2Futil%2FSchemaContextUtil.java;h=1d702c26d842d27af07b52ab1d7fb49112df8195;hp=44ef804e2c0c9dd9bb10223d9bf6fafaaf5b49c3;hb=refs%2Fchanges%2F03%2F703%2F1;hpb=4731ee462f09ad75d31a175b0dd5abfa11eb2b6a diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java index 44ef804e2c..1d702c26d8 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java @@ -16,99 +16,254 @@ import java.util.Set; import org.opendaylight.controller.yang.common.QName; import org.opendaylight.controller.yang.model.api.*; +/** + * The Schema Context Util contains support methods for searching through Schema Context modules for specified schema + * nodes via Schema Path or Revision Aware XPath. The Schema Context Util is designed as mixin, + * so it is not instantiable. + * + * @author Lukas Sedlak + */ public final class SchemaContextUtil { private SchemaContextUtil() { } + /** + * Method attempts to find DataSchemaNode in Schema Context via specified Schema Path. The returned + * DataSchemaNode from method will be the node at 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 IllegalArgumentException. + * + * @throws IllegalArgumentException + * + * @param context + * Schema Context + * @param schemaPath + * Schema Path to search for + * @return DataSchemaNode from the end of the Schema Path or + * null if the Node is not present. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) { - if (schemaPath != null) { - final Module module = resolveModuleFromSchemaPath(context, schemaPath); - final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((module != null) && (prefixedPath != null)) { - return findSchemaNodeForGivenPath(context, module, prefixedPath); - } + final Module module = resolveModuleFromSchemaPath(context, schemaPath); + final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + + if ((module != null) && (prefixedPath != null)) { + return findSchemaNodeForGivenPath(context, module, prefixedPath); } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise the + * operation would fail and return null. + *
+ * The Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in path, + * because in this state the Schema Context is completely unaware of data state and will be not able to properly + * resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * In case that Schema Context or Module or Revision Aware XPath contains null references the method + * will throw IllegalArgumentException + *
+ * If the Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in depending + * module in Schema Context 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 Yang Module + * @param nonCondXPath Non Conditional Revision Aware XPath + * @return Returns Data Schema Node for specified Schema Context for given Non-conditional Revision Aware XPath, + * or null if the DataSchemaNode is not present in Schema Context. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final Module module, final RevisionAwareXPath nonCondXPath) { - if (nonCondXPath != null) { - final String strXPath = nonCondXPath.toString(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (nonCondXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } - if (strXPath != null) { - if (strXPath.matches(".*//[.* | .*//].*")) { - // TODO: function to escape conditions in path - } - if (nonCondXPath.isAbsolute()) { - final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); - if (qnamedPath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); - return dataNode; - } + final String strXPath = nonCondXPath.toString(); + if (strXPath != null) { + if (strXPath.contains("[")) { + throw new IllegalArgumentException("Revision Aware XPath cannot contains condition!"); + } + if (nonCondXPath.isAbsolute()) { + final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); + if (qnamedPath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); + return dataNode; } } } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional relative Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise + * the operation would fail and return null. + *
+ * The relative Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in + * path, because in this state the Schema Context is completely unaware of data state and will be not able to + * properly resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * The Actual Schema Node MUST be specified correctly because from this Schema Node will search starts. If the + * Actual Schema Node is not correct the operation will simply fail, because it will be unable to find desired + * DataSchemaNode. + *
+ * In case that Schema Context or Module or Actual Schema Node or relative Revision Aware XPath contains + * null references the method will throw IllegalArgumentException + *
+ * If the Revision Aware XPath doesn't have flag isAbsolute == false the method will + * throw IllegalArgumentException. + *
+ * If the relative Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in + * depending module in Schema Context 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 Yang Module + * @param actualSchemaNode Actual Schema Node + * @param relativeXPath Relative Non Conditional Revision Aware XPath + * @return DataSchemaNode if is present in specified Schema Context for given relative Revision Aware XPath, + * otherwise will return null. + */ public static DataSchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module, final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) { - if ((actualSchemaNode != null) && (relativeXPath != null) && !relativeXPath.isAbsolute()) { + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (actualSchemaNode == null) { + throw new IllegalArgumentException("Actual Schema Node reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } - final SchemaPath actualNodePath = actualSchemaNode.getPath(); - if (actualNodePath != null) { - final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); + final SchemaPath actualNodePath = actualSchemaNode.getPath(); + if (actualNodePath != null) { + final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); - if (qnamePath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); - return dataNode; - } + if (qnamePath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); + return dataNode; } } - return null; } + /** + * Retrieve information from Schema Path and returns the module reference to which Schema Node belongs. The + * search for correct Module is based on namespace within the last item in Schema Path. If schema context + * contains module with namespace specified in last item of Schema Path, then operation will returns Module + * reference, otherwise returns null + *
+ * If Schema Context or Schema Node contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param schemaPath Schema Path + * @return Module reference for given Schema Path if module is present in Schema Context, + * otherwise returns null + */ private static Module resolveModuleFromSchemaPath(final SchemaContext context, final SchemaPath schemaPath) { - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - final List path = schemaPath.getPath(); - if (!path.isEmpty()) { - final QName qname = path.get(path.size() - 1); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + final List path = schemaPath.getPath(); + if (!path.isEmpty()) { + final QName qname = path.get(path.size() - 1); + + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } } + return null; } + /** + * Returns the Yang Module from specified Schema Context in which the TypeDefinition is declared. If the + * TypeDefinition si not present in Schema Context then the method will return null + * + * If Schema Context or TypeDefinition contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param type Type Definition + * @return Yang Module in which the TypeDefinition is declared, if is not present, returns null. + */ public static Module findParentModuleForTypeDefinition(final SchemaContext context, final TypeDefinition type) { final SchemaPath schemaPath = type.getPath(); - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - if (type instanceof ExtendedType) { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 1); - - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } - } else { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 2); + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } + final List qnamedPath = schemaPath.getPath(); + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("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."); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + if (type instanceof ExtendedType) { + final QName qname = qnamedPath.get(qnamedPath.size() - 1); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); + } + } else { + final QName qname = qnamedPath.get(qnamedPath.size() - 2); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } - } return null; } + /** + * Returns parent Yang Module for specified Schema Context in which Schema Node is declared. 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 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 + */ public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) { if (context == null) { throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); @@ -132,120 +287,246 @@ public final class SchemaContextUtil { return context.findModuleByNamespace(qname.getNamespace()); } + /** + * Method will attempt to find DataSchemaNode from specified Module and Queue of QNames through the Schema + * Context. The QNamed path could be defined across multiple modules in Schema Context so the method is called + * recursively. If the QNamed path contains QNames that are not part of any Module or Schema Context Path the + * operation will fail and returns null + *
+ * If Schema Context, Module or Queue of QNames refers to null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param qnamedPath Queue of QNames + * @return DataSchemaNode if is present in Module(s) for specified Schema Context and given QNamed Path, + * otherwise will return null. + */ private static DataSchemaNode findSchemaNodeForGivenPath(final SchemaContext context, final Module module, final Queue qnamedPath) { - if ((module != null) && (module.getNamespace() != null) && (qnamedPath != null)) { - DataNodeContainer nextNode = module; - final URI moduleNamespace = module.getNamespace(); - - QName childNodeQName; - DataSchemaNode schemaNode = null; - while ((nextNode != null) && !qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - if (childNodeQName != null) { - final URI childNodeNamespace = childNodeQName.getNamespace(); - - schemaNode = nextNode.getDataChildByName(childNodeQName); - if (schemaNode != null) { - if (schemaNode instanceof ContainerSchemaNode) { - nextNode = (ContainerSchemaNode) schemaNode; - } else if (schemaNode instanceof ListSchemaNode) { - nextNode = (ListSchemaNode) schemaNode; - } else if (schemaNode instanceof ChoiceNode) { - final ChoiceNode choice = (ChoiceNode) schemaNode; - qnamedPath.poll(); - if (!qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - nextNode = choice.getCaseNodeByName(childNodeQName); - schemaNode = (DataSchemaNode)nextNode; - } - } else { - nextNode = null; + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (module.getNamespace() == null) { + throw new IllegalArgumentException("Namespace for Module cannot contains NULL reference!"); + } + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("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."); + } + + DataNodeContainer nextNode = module; + final URI moduleNamespace = module.getNamespace(); + + QName childNodeQName; + DataSchemaNode schemaNode = null; + while ((nextNode != null) && !qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + if (childNodeQName != null) { + final URI childNodeNamespace = childNodeQName.getNamespace(); + + schemaNode = nextNode.getDataChildByName(childNodeQName); + if (schemaNode != null) { + if (schemaNode instanceof ContainerSchemaNode) { + nextNode = (ContainerSchemaNode) schemaNode; + } else if (schemaNode instanceof ListSchemaNode) { + nextNode = (ListSchemaNode) schemaNode; + } else if (schemaNode instanceof ChoiceNode) { + final ChoiceNode choice = (ChoiceNode) schemaNode; + qnamedPath.poll(); + if (!qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + nextNode = choice.getCaseNodeByName(childNodeQName); + schemaNode = (DataSchemaNode) nextNode; } - } else if (!childNodeNamespace.equals(moduleNamespace)) { - final Module nextModule = context.findModuleByNamespace(childNodeNamespace); - schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); - return schemaNode; + } else { + nextNode = null; } - qnamedPath.poll(); + } else if (!childNodeNamespace.equals(moduleNamespace)) { + final Module nextModule = context.findModuleByNamespace(childNodeNamespace); + schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); + return schemaNode; } + qnamedPath.poll(); } - return schemaNode; } - return null; + return schemaNode; } + /** + * Transforms string representation of XPath to Queue of QNames. The XPath is split by "/" and for each part of + * XPath is assigned correct module in Schema Path. + *
+ * If Schema Context, Parent Module or XPath string contains null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param parentModule Parent Module + * @param xpath XPath String + * @return + */ private static Queue xpathToQNamePath(final SchemaContext context, final Module parentModule, final String xpath) { - final Queue path = new LinkedList<>(); - if (xpath != null) { - final String[] prefixedPath = xpath.split("/"); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (xpath == null) { + throw new IllegalArgumentException("XPath string reference cannot be NULL!"); + } - for (int i = 0; i < prefixedPath.length; ++i) { - if (!prefixedPath[i].isEmpty()) { - path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); - } + final Queue path = new LinkedList<>(); + final String[] prefixedPath = xpath.split("/"); + for (int i = 0; i < prefixedPath.length; ++i) { + if (!prefixedPath[i].isEmpty()) { + path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); } } return path; } + /** + * Transforms part of Prefixed Path as java String to QName. + *
+ * If the string contains module prefix separated by ":" (i.e. mod:container) this module is provided from from + * Parent Module list of imports. If the Prefixed module is present in Schema Context the QName can be + * constructed. + *
+ * If the Prefixed Path Part does not contains prefix the Parent's Module namespace is taken for construction of + * QName. + *
+ * 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 Parent Module + * @param prefixedPathPart Prefixed Path Part string + * @return QName from prefixed Path Part String. + */ private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, final String prefixedPathPart) { - if (parentModule != null && prefixedPathPart != null) { - if (prefixedPathPart.contains(":")) { - final String[] prefixedName = prefixedPathPart.split(":"); - final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); - if (module != null) { - return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); - } - } else { - return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (prefixedPathPart == null) { + throw new IllegalArgumentException("Prefixed Path Part cannot be NULL!"); + } + + if (prefixedPathPart.contains(":")) { + final String[] prefixedName = prefixedPathPart.split(":"); + final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); + if (module != null) { + return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); } + } else { + return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } return null; } + /** + * Method will attempt to resolve and provide Module reference for specified module prefix. Each Yang module + * could contains multiple imports which MUST be associated with corresponding module prefix. The method simply + * looks into module imports and returns the module that is bounded with specified prefix. If the prefix is not + * present in module or the prefixed module is not present in specified Schema Context, + * the method will return null. + *
+ * If String prefix is the same as prefix of the specified Module the reference to this module is returned. + *
+ * If Schema Context, Module or Prefix are referring to null the method will return + * IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param prefix Module Prefix + * @return Module for given prefix in specified Schema Context if is present, otherwise returns null + */ private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) { - if ((module != null) && (prefix != null)) { - if (prefix.equals(module.getPrefix())) { - return module; - } + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (prefix == null) { + throw new IllegalArgumentException("Prefix string cannot be NULL!"); + } - final Set imports = module.getImports(); + if (prefix.equals(module.getPrefix())) { + return module; + } - for (final ModuleImport mi : imports) { - if (prefix.equals(mi.getPrefix())) { - return context.findModuleByName(mi.getModuleName(), mi.getRevision()); - } + final Set imports = module.getImports(); + for (final ModuleImport mi : imports) { + if (prefix.equals(mi.getPrefix())) { + return context.findModuleByName(mi.getModuleName(), mi.getRevision()); } } return null; } + /** + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param relativeXPath Non conditional Revision Aware Relative XPath + * @param leafrefSchemaPath Schema Path for Leafref + * @return + */ private static Queue resolveRelativeXPath(final SchemaContext context, final Module module, final RevisionAwareXPath relativeXPath, final SchemaPath leafrefSchemaPath) { final Queue absolutePath = new LinkedList<>(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } + if (leafrefSchemaPath == null) { + throw new IllegalArgumentException("Schema Path reference for Leafref cannot be NULL!"); + } - if ((module != null) && (relativeXPath != null) && !relativeXPath.isAbsolute() && (leafrefSchemaPath != null)) { - final String strXPath = relativeXPath.toString(); - if (strXPath != null) { - final String[] xpaths = strXPath.split("/"); - - if (xpaths != null) { - int colCount = 0; - while (xpaths[colCount].contains("..")) { - ++colCount; + final String strXPath = relativeXPath.toString(); + if (strXPath != null) { + final String[] xpaths = strXPath.split("/"); + if (xpaths != null) { + int colCount = 0; + while (xpaths[colCount].contains("..")) { + ++colCount; + } + final List path = leafrefSchemaPath.getPath(); + if (path != null) { + int lenght = path.size() - colCount - 1; + for (int i = 0; i < lenght; ++i) { + absolutePath.add(path.get(i)); } - final List path = leafrefSchemaPath.getPath(); - if (path != null) { - int lenght = path.size() - colCount - 1; - for (int i = 0; i < lenght; ++i) { - absolutePath.add(path.get(i)); - } - for (int i = colCount; i < xpaths.length; ++i) { - absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); - } + for (int i = colCount; i < xpaths.length; ++i) { + absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); } } }