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=fc98c1daf0aef88d6e202743d0db8e3fcb56576d;hb=45dba97a115720dfae3f7aadc672aeabfa894cc0;hp=0dc0c19e6b19d2b7e539052d2c15bab45848a6b7;hpb=85c0405ed187f2d00d47c12c20f3c5ab8029cd2f;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 0dc0c19e6b..fc98c1daf0 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 @@ -7,12 +7,17 @@ */ package org.opendaylight.yangtools.yang.model.util; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -39,8 +44,6 @@ import org.opendaylight.yangtools.yang.model.api.UsesNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - /** * The Schema Context Util contains support methods for searching through Schema * Context modules for specified schema nodes via Schema Path or Revision Aware @@ -50,6 +53,8 @@ import com.google.common.base.Preconditions; */ public final class SchemaContextUtil { private static final Logger LOG = LoggerFactory.getLogger(SchemaContextUtil.class); + private static final Splitter COLON_SPLITTER = Splitter.on(':'); + private static final Splitter SLASH_SPLITTER = Splitter.on('/'); private SchemaContextUtil() { } @@ -185,7 +190,7 @@ public final class SchemaContextUtil { SchemaPath actualNodePath = actualSchemaNode.getPath(); if (actualNodePath != null) { - List qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode); + Iterable qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode); if (qnamePath != null) { return findNodeInSchemaContext(context, qnamePath); @@ -217,18 +222,15 @@ public final class SchemaContextUtil { Preconditions.checkState(schemaNode.getPath() != null, "Schema Path for Schema Node is not " + "set properly (Schema Path is NULL)"); - List qnamedPath = schemaNode.getPath().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."); - } - QName qname = qnamedPath.get(qnamedPath.size() - 1); + final QName qname = Iterables.getFirst(schemaNode.getPath().getPathTowardsRoot(), null); + 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()); } - public static SchemaNode findNodeInSchemaContext(final SchemaContext context, final List path) { - final QName current = path.get(0); + 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()); @@ -266,8 +268,8 @@ public final class SchemaContextUtil { return (GroupingDefinition) currentParent; } - private static SchemaNode findNodeInModule(final Module module, final List path) { - final QName current = path.get(0); + private static SchemaNode findNodeInModule(final Module module, final Iterable path) { + final QName current = path.iterator().next(); LOG.trace("Looking for data container {} in module {}", current, module); SchemaNode parent = module.getDataChildByName(current); @@ -309,14 +311,14 @@ public final class SchemaContextUtil { return null; } - private static SchemaNode findNodeInGrouping(final GroupingDefinition grouping, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNodeInGrouping(final GroupingDefinition grouping, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { LOG.debug("Found grouping {}", grouping); return grouping; } LOG.trace("Looking for path {} in grouping {}", path, grouping); - final QName current = path.get(0); final DataSchemaNode node = grouping.getDataChildByName(current); if (node == null) { LOG.debug("No node matching {} found in grouping {}", current, grouping); @@ -326,14 +328,14 @@ public final class SchemaContextUtil { return findNode(node, nextLevel(path)); } - private static SchemaNode findNodeInRpc(final RpcDefinition rpc, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNodeInRpc(final RpcDefinition rpc, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { LOG.debug("Found RPC {}", rpc); return rpc; } LOG.trace("Looking for path {} in rpc {}", path, rpc); - final QName current = path.get(0); switch (current.getLocalName()) { case "input": return findNode(rpc.getInput(), nextLevel(path)); @@ -345,14 +347,14 @@ public final class SchemaContextUtil { } } - private static SchemaNode findNodeInNotification(final NotificationDefinition ntf, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNodeInNotification(final NotificationDefinition ntf, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { LOG.debug("Found notification {}", ntf); return ntf; } LOG.trace("Looking for path {} in notification {}", path, ntf); - final QName current = path.get(0); DataSchemaNode node = ntf.getDataChildByName(current); if (node == null) { LOG.debug("No node matching {} found in notification {}", current, ntf); @@ -362,11 +364,11 @@ public final class SchemaContextUtil { return findNode(node, nextLevel(path)); } - private static SchemaNode findNode(final ChoiceNode parent, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNode(final ChoiceNode parent, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { return parent; } - QName current = path.get(0); ChoiceCaseNode node = parent.getCaseNodeByName(current); if (node != null) { return findNodeInCase(node, nextLevel(path)); @@ -374,12 +376,12 @@ public final class SchemaContextUtil { return null; } - private static SchemaNode findNode(final ContainerSchemaNode parent, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNode(final ContainerSchemaNode parent, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { return parent; } - final QName current = path.get(0); final DataSchemaNode node = parent.getDataChildByName(current); if (node == null) { LOG.debug("Failed to find {} in parent {}", path, parent); @@ -389,12 +391,12 @@ public final class SchemaContextUtil { return findNode(node, nextLevel(path)); } - private static SchemaNode findNode(final ListSchemaNode parent, final List path) { - if (path.isEmpty()) { + private static SchemaNode findNode(final ListSchemaNode parent, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { return parent; } - QName current = path.get(0); DataSchemaNode node = parent.getDataChildByName(current); if (node == null) { LOG.debug("Failed to find {} in parent {}", path, parent); @@ -403,9 +405,9 @@ public final class SchemaContextUtil { return findNode(node, nextLevel(path)); } - private static SchemaNode findNode(final DataSchemaNode parent, final List path) { + private static SchemaNode findNode(final DataSchemaNode parent, final Iterable path) { final SchemaNode node; - if (!path.isEmpty()) { + if (!Iterables.isEmpty(path)) { if (parent instanceof ContainerSchemaNode) { node = findNode((ContainerSchemaNode) parent, path); } else if (parent instanceof ListSchemaNode) { @@ -427,12 +429,12 @@ public final class SchemaContextUtil { return node; } - public static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final List path) { - if (path.isEmpty()) { + public static SchemaNode findNodeInCase(final ChoiceCaseNode parent, final Iterable path) { + final QName current = Iterables.getFirst(path, null); + if (current == null) { return parent; } - QName current = path.get(0); DataSchemaNode node = parent.getDataChildByName(current); if (node == null) { LOG.debug("Failed to find {} in parent {}", path, parent); @@ -450,8 +452,8 @@ public final class SchemaContextUtil { return null; } - private static List nextLevel(final List path) { - return path.subList(1, path.size()); + private static Iterable nextLevel(final Iterable path) { + return Iterables.skip(path, 1); } public static NotificationDefinition getNotificationByName(final Module module, final QName name) { @@ -491,69 +493,82 @@ public final class SchemaContextUtil { return result; } - private static DataSchemaNode findCorrectTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) { - if (node.getPath().getPath().size() == 1) { - // uses is under module statement - Module m = findParentModule(ctx, node); - DataSchemaNode result = null; - for (UsesNode u : m.getUses()) { - SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath()); - if (!(targetGrouping instanceof GroupingDefinition)) { - throw new IllegalArgumentException(String.format("Failed to generate code for augment in %s", u)); - } - GroupingDefinition gr = (GroupingDefinition) targetGrouping; - result = gr.getDataChildByName(node.getQName().getLocalName()); - } - if (result == null) { - throw new IllegalArgumentException("Failed to generate code for augment"); + private static DataSchemaNode findCorrectImmediateTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) { + // uses is under module statement + final Module m = findParentModule(ctx, node); + Preconditions.checkArgument(m != null, "Failed to find module for node {} in context {}", node, ctx); + + for (final UsesNode u : m.getUses()) { + final SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPathFromRoot()); + Preconditions.checkArgument(targetGrouping instanceof GroupingDefinition, + "Failed to generate code for augment in %s", u); + + LOG.trace("Checking grouping {} for node {}", targetGrouping, node); + final GroupingDefinition gr = (GroupingDefinition) targetGrouping; + final DataSchemaNode result = gr.getDataChildByName(node.getQName().getLocalName()); + if (result != null) { + return result; } - return result; - } else { - DataSchemaNode result = null; + + LOG.debug("Skipped grouping {}, no matching node found", gr); + } + + throw new IllegalArgumentException( + String.format("Failed to find uses node matching {} in context {}", node, ctx)); + } + + private static DataSchemaNode findCorrectTargetFromGrouping(final DataSchemaNode node, final SchemaContext ctx) { + if (node.getPath().getPath().size() != 1) { QName currentName = node.getQName(); + // tmpPath is used to track level of nesting List tmpPath = new ArrayList<>(); Object parent = null; - SchemaPath sp = node.getPath(); - List names = sp.getPath(); - List newNames = new ArrayList<>(names); - newNames.remove(newNames.size() - 1); - SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute()); - parent = findDataSchemaNode(ctx, newSp); + // create schema path of parent node + SchemaPath sp = node.getPath().getParent(); + parent = findDataSchemaNode(ctx, sp); do { tmpPath.add(currentName); + + DataSchemaNode result = null; + // search parent node's used groupings for presence of wanted + // node if (parent instanceof DataNodeContainer) { DataNodeContainer dataNodeParent = (DataNodeContainer) parent; for (UsesNode u : dataNodeParent.getUses()) { - if (result == null) { - result = getResultFromUses(u, currentName.getLocalName(), ctx); + result = getResultFromUses(u, currentName.getLocalName(), ctx); + if (result != null) { + break; } } } + + // if node is not found in any of current parent's used + // groupings => parent is added by grouping too, so repeat same + // process for parent if (result == null) { - currentName = ((SchemaNode) parent).getQName(); - if (parent instanceof SchemaNode) { - SchemaPath nodeSp = ((SchemaNode) parent).getPath(); - List nodeNames = nodeSp.getPath(); - List nodeNewNames = new ArrayList<>(nodeNames); - nodeNewNames.remove(nodeNewNames.size() - 1); - if (nodeNewNames.isEmpty()) { - parent = getParentModule((SchemaNode) parent, ctx); - } else { - SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.isAbsolute()); - parent = findDataSchemaNode(ctx, nodeNewSp); - } - } else { - throw new IllegalArgumentException("Failed to generate code for augment"); - } + final SchemaNode sn = (SchemaNode) parent; + + // set current name to name of parent node + currentName = sn.getQName(); + Preconditions.checkArgument(parent instanceof SchemaNode, + "Failed to generate code for augmend node {} at parent {}", node, parent); + + // create schema path for parent of current parent + final SchemaPath parentSp = sn.getPath().getParent(); + parent = parentSp.getPathFromRoot().iterator().hasNext() ? findDataSchemaNode(ctx, parentSp) + : getParentModule(sn, ctx); + } else { + // if wanted node was found in grouping, traverse this node + // based on level of nesting + return getTargetNode(tmpPath, result, ctx); } - } while (result == null && !(parent instanceof Module)); + } while (!(parent instanceof Module)); - if (result != null) { - result = getTargetNode(tmpPath, result, ctx); - } - return result; + return null; + } else { + return findCorrectImmediateTargetFromGrouping(node, ctx); } } @@ -571,11 +586,7 @@ public final class SchemaContextUtil { AugmentationSchema augment = null; do { SchemaPath sp = ((SchemaNode) parent).getPath(); - List names = sp.getPath(); - List newNames = new ArrayList<>(names); - newNames.remove(newNames.size() - 1); - SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute()); - parent = findDataSchemaNode(ctx, newSp); + parent = findDataSchemaNode(ctx, sp.getParent()); if (parent instanceof AugmentationTarget) { tmpPath.add(currentName); tmpTree.add((SchemaNode) currentNode); @@ -615,7 +626,7 @@ public final class SchemaContextUtil { } private static DataSchemaNode getResultFromUses(final UsesNode u, final String currentName, final SchemaContext ctx) { - SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath()); + SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPathFromRoot()); Preconditions.checkArgument(targetGrouping instanceof GroupingDefinition, "Failed to generate code for augment in %s", u); @@ -624,7 +635,7 @@ public final class SchemaContextUtil { } private static Module getParentModule(final SchemaNode node, final SchemaContext ctx) { - QName qname = node.getPath().getPath().get(0); + QName qname = node.getPath().getPathFromRoot().iterator().next(); URI namespace = qname.getNamespace(); Date revision = qname.getRevision(); return ctx.findModuleByNamespaceAndRevision(namespace, revision); @@ -733,8 +744,7 @@ public final class SchemaContextUtil { Preconditions.checkArgument(xpath != null, "XPath string reference cannot be NULL"); List path = new LinkedList(); - String[] prefixedPath = xpath.split("/"); - for (String pathComponent : prefixedPath) { + for (String pathComponent : SLASH_SPLITTER.split(xpath)) { if (!pathComponent.isEmpty()) { path.add(stringPathPartToQName(context, parentModule, pathComponent)); } @@ -768,14 +778,18 @@ public final class SchemaContextUtil { Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL"); Preconditions.checkArgument(prefixedPathPart != null, "Prefixed Path Part cannot be NULL!"); - if (prefixedPathPart.contains(":")) { - String[] prefixedName = prefixedPathPart.split(":"); - Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); + if (prefixedPathPart.indexOf(':') != -1) { + final Iterator prefixedName = COLON_SPLITTER.split(prefixedPathPart).iterator(); + final String modulePrefix = prefixedName.next(); + + Module module = resolveModuleForPrefix(context, parentModule, modulePrefix); Preconditions.checkArgument(module != null, "Failed to resolve xpath: no module found for prefix %s in module %s", - prefixedName[0], parentModule.getName()); - return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); + modulePrefix, parentModule.getName()); + + // FIXME: Module should have a QNameModule handle + return QName.create(module.getNamespace(), module.getRevision(), prefixedName.next()); } else { - return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); + return QName.create(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } } @@ -834,7 +848,7 @@ public final class SchemaContextUtil { * Schema Path for Leafref * @return list of QName */ - private static List resolveRelativeXPath(final SchemaContext context, final Module module, + private static Iterable resolveRelativeXPath(final SchemaContext context, final Module module, final RevisionAwareXPath relativeXPath, final SchemaNode leafrefParentNode) { Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL"); Preconditions.checkArgument(module != null, "Module reference cannot be NULL"); @@ -845,27 +859,22 @@ public final class SchemaContextUtil { Preconditions.checkState(leafrefParentNode.getPath() != null, "Schema Path reference for Leafref cannot be NULL"); - List absolutePath = new LinkedList(); - String strXPath = relativeXPath.toString(); - String[] xpaths = strXPath.split("/"); + final Iterable xpaths = SLASH_SPLITTER.split(relativeXPath.toString()); + // Find out how many "parent" components there are + // FIXME: is .contains() the right check here? int colCount = 0; - while (xpaths[colCount].contains("..")) { - colCount = colCount + 1; - } - List path = leafrefParentNode.getPath().getPath(); - if (path != null) { - int lenght = path.size() - colCount; - absolutePath.addAll(path.subList(0, lenght)); - List xpathsList = Arrays.asList(xpaths); - List sublistedXPath = xpathsList.subList(colCount, xpaths.length); - List sublist = new ArrayList<>(); - for (String pathPart : sublistedXPath) { - sublist.add(stringPathPartToQName(context, module, pathPart)); - } - absolutePath.addAll(sublist); + for (Iterator it = xpaths.iterator(); it.hasNext() && it.next().contains(".."); ) { + ++colCount; } - return absolutePath; + final Iterable parent = leafrefParentNode.getPath().getPathFromRoot(); + return Iterables.concat(Iterables.limit(parent, Iterables.size(parent) - colCount), + Iterables.transform(Iterables.skip(xpaths, colCount), new Function() { + @Override + public QName apply(final String input) { + return stringPathPartToQName(context, module, input); + } + })); } }