X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fbuilder%2Fimpl%2FBuilderUtils.java;h=792db8d9c84b8a1a677df8511343fa097565845b;hb=42abb28b99a02f9580f4676ce5c315628e5bcd24;hp=082ff6953837f19fe57d22e48a22f4814db5ffe4;hpb=b4c4e3aa99c2c6306f4c8be211523308b2431930;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java index 082ff69538..792db8d9c8 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java @@ -12,9 +12,9 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; import com.google.common.io.ByteSource; - -import java.io.ByteArrayOutputStream; +import com.google.common.io.ByteStreams; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -23,17 +23,28 @@ import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; import java.util.Set; import java.util.TreeMap; -import org.apache.commons.io.IOUtils; +import org.antlr.v4.runtime.tree.ParseTree; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; 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.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -57,20 +68,28 @@ import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember; import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; +import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; +import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils; +import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo; import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream; import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream; import org.opendaylight.yangtools.yang.parser.util.YangParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ +@Deprecated public final class BuilderUtils { private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class); - private static final Splitter SLASH_SPLITTER = Splitter.on('/'); private static final Splitter COLON_SPLITTER = Splitter.on(':'); + private static final Date NULL_DATE = new Date(0L); private static final String INPUT = "input"; private static final String OUTPUT = "output"; + private static final String CHILD_NOT_FOUND_IN_NODE_STR = "Child {} not found in node {}"; private BuilderUtils() { } @@ -107,41 +126,6 @@ public final class BuilderUtils { }); } - /** - * Create new SchemaPath from given path and qname. - * - * @param schemaPath - * base path - * @param qname - * one or more qnames added to base path - * @return new SchemaPath from given path and qname - * - * @deprecated Use {@link SchemaPath#createChild(QName...)} instead. - */ - @Deprecated - public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) { - return schemaPath.createChild(qname); - } - - /** - * Get module import referenced by given prefix. - * - * @param builder - * module to search - * @param prefix - * prefix associated with import - * @return ModuleImport based on given prefix - */ - public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) { - for (ModuleImport mi : builder.getModuleImports()) { - if (mi.getPrefix().equals(prefix)) { - return mi; - - } - } - return null; - } - /** * Find dependent module based on given prefix * @@ -155,24 +139,24 @@ public final class BuilderUtils { * current line in yang model * @return module builder if found, null otherwise */ - public static ModuleBuilder findModuleFromBuilders(final Map> modules, + public static ModuleBuilder findModuleFromBuilders(final Map> modules, final ModuleBuilder module, final String prefix, final int line) { - ModuleBuilder dependentModule = null; - Date dependentModuleRevision = null; + ModuleBuilder dependentModule; + Date dependentModuleRevision; if (prefix == null) { dependentModule = module; } else if (prefix.equals(module.getPrefix())) { dependentModule = module; } else { - ModuleImport dependentModuleImport = getModuleImport(module, prefix); + ModuleImport dependentModuleImport = module.getImport(prefix); if (dependentModuleImport == null) { throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'."); } String dependentModuleName = dependentModuleImport.getModuleName(); dependentModuleRevision = dependentModuleImport.getRevision(); - TreeMap moduleBuildersByRevision = modules.get(dependentModuleName); + NavigableMap moduleBuildersByRevision = modules.get(dependentModuleName); if (moduleBuildersByRevision == null) { return null; } @@ -185,6 +169,24 @@ public final class BuilderUtils { return dependentModule; } + public static ModuleBuilder findModuleFromBuilders(final ModuleImport imp, final Iterable modules) { + String name = imp.getModuleName(); + Date revision = imp.getRevision(); + NavigableMap map = new TreeMap<>(); + for (ModuleBuilder module : modules) { + if (module != null && module.getName().equals(name)) { + map.put(module.getRevision(), module); + } + } + if (map.isEmpty()) { + return null; + } + if (revision == null) { + return map.lastEntry().getValue(); + } + return map.get(revision); + } + /** * Find module from context based on prefix. * @@ -193,20 +195,19 @@ public final class BuilderUtils { * @param currentModule * current module * @param prefix - * current prefix used to reference dependent module + * prefix used to reference dependent module * @param line * current line in yang model - * @return module based on given prefix if found in context, null otherwise + * @return module based on import with given prefix if found in context, + * null otherwise + * @throws YangParseException + * if no import found with given prefix */ public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule, final String prefix, final int line) { - if (context == null) { - throw new YangParseException(currentModule.getName(), line, "Cannot find module with prefix '" + prefix - + "'."); - } - TreeMap modulesByRevision = new TreeMap<>(); + NavigableMap modulesByRevision = new TreeMap<>(); - ModuleImport dependentModuleImport = BuilderUtils.getModuleImport(currentModule, prefix); + ModuleImport dependentModuleImport = currentModule.getImport(prefix); if (dependentModuleImport == null) { throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'."); } @@ -217,47 +218,23 @@ public final class BuilderUtils { if (contextModule.getName().equals(dependentModuleName)) { Date revision = contextModule.getRevision(); if (revision == null) { - revision = new Date(0L); + revision = NULL_DATE; } modulesByRevision.put(revision, contextModule); } } - Module result = null; + Module result; if (dependentModuleRevision == null) { result = modulesByRevision.get(modulesByRevision.firstKey()); } else { result = modulesByRevision.get(dependentModuleRevision); } - return result; - } - - /** - * Parse XPath string. - * - * @param xpathString - * XPath as String - * @return SchemaPath from given String - */ - public static SchemaPath parseXPathString(final String xpathString) { - final boolean absolute = xpathString.indexOf('/') == 0; - - final List path = new ArrayList(); - for (String pathElement : SLASH_SPLITTER.split(xpathString)) { - if (pathElement.length() > 0) { - final Iterator it = COLON_SPLITTER.split(pathElement).iterator(); - final String s = it.next(); - - final QName name; - if (it.hasNext()) { - name = new QName(null, null, s, it.next()); - } else { - name = new QName(null, null, null, s); - } - path.add(name); - } + if (result == null) { + throw new YangParseException(currentModule.getName(), line, "Module not found for prefix " + prefix); } - return SchemaPath.create(path, absolute); + + return result; } /** @@ -355,7 +332,7 @@ public final class BuilderUtils { /** * Set addedByUses flag to true for node and all its child nodes. * - * @param node + * @param node grouping member node */ public static void setNodeAddedByUses(final GroupingMember node) { node.setAddedByUses(true); @@ -373,55 +350,72 @@ public final class BuilderUtils { } /** - * Set config flag to new value. + * Find builder of schema node under parent builder (including under + * AugmentationSchemaBuilder). * - * @param node - * node to update - * @param config - * new config value + * @param path + * - path of target schema node builder + * @param parent + * - base data node container builder under which the target + * schema node builder should be found + * @return builder of schema node */ - public static void setNodeConfig(final DataSchemaNodeBuilder node, final Boolean config) { - if (node instanceof ContainerSchemaNodeBuilder || node instanceof LeafSchemaNodeBuilder - || node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder - || node instanceof ChoiceBuilder || node instanceof AnyXmlBuilder) { - node.setConfiguration(config); - } - if (node instanceof DataNodeContainerBuilder) { - DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node; - for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) { - setNodeConfig(inner, config); - } - } else if (node instanceof ChoiceBuilder) { - ChoiceBuilder choiceChild = (ChoiceBuilder) node; - for (ChoiceCaseBuilder inner : choiceChild.getCases()) { - setNodeConfig(inner, config); + public static SchemaNodeBuilder findTargetNode(final Iterable path, + final DataNodeContainerBuilder parent) { + + Preconditions.checkNotNull(parent); + Preconditions.checkNotNull(path); + + SchemaNodeBuilder foundNode = null; + + final Iterator pathIterator = path.iterator(); + if (pathIterator.hasNext()) { + String name = pathIterator.next().getLocalName(); + foundNode = parent.getDataChildByName(name); + if (foundNode == null) { + foundNode = findUnknownNode(name, parent); } } + + if (pathIterator.hasNext() && foundNode != null) { + return findSchemaNode(Iterables.skip(path, 1), foundNode); + } else { + return foundNode; + } } - public static DataSchemaNodeBuilder findSchemaNode(final List path, final SchemaNodeBuilder parentNode) { - DataSchemaNodeBuilder node = null; + public static SchemaNodeBuilder findSchemaNode(final Iterable path, final SchemaNodeBuilder parentNode) { + SchemaNodeBuilder node = null; SchemaNodeBuilder parent = parentNode; + int size = Iterables.size(path); int i = 0; - while (i < path.size()) { - String name = path.get(i).getLocalName(); + for (QName qname : path) { + String name = qname.getLocalName(); if (parent instanceof DataNodeContainerBuilder) { node = ((DataNodeContainerBuilder) parent).getDataChildByName(name); + if (node == null) { + node = findUnknownNode(name, parent); + } } else if (parent instanceof ChoiceBuilder) { node = ((ChoiceBuilder) parent).getCaseNodeByName(name); + if (node == null) { + node = findUnknownNode(name, parent); + } } else if (parent instanceof RpcDefinitionBuilder) { - if ("input".equals(name)) { + if (INPUT.equals(name)) { node = ((RpcDefinitionBuilder) parent).getInput(); - } else if ("output".equals(name)) { + } else if (OUTPUT.equals(name)) { node = ((RpcDefinitionBuilder) parent).getOutput(); } else { - return null; + if (node == null) { + node = findUnknownNode(name, parent); + } } } else { - return null; + node = findUnknownNode(name, parent); } - if (i < path.size() - 1) { + if (i < size - 1) { parent = node; } i = i + 1; @@ -430,6 +424,15 @@ public final class BuilderUtils { return node; } + private static UnknownSchemaNodeBuilder findUnknownNode(final String name, final Builder parent) { + for (UnknownSchemaNodeBuilder un : parent.getUnknownNodes()) { + if (un.getQName().getLocalName().equals(name)) { + return un; + } + } + return null; + } + /** * * Find a builder for node in data namespace of YANG module. @@ -456,7 +459,16 @@ public final class BuilderUtils { Optional currentNode = getDataNamespaceChild(module, first); while (currentNode.isPresent() && path.hasNext()) { - currentNode = findDataChild(currentNode.get(), path.next()); + SchemaNodeBuilder currentParent = currentNode.get(); + QName currentPath = path.next(); + currentNode = findDataChild(currentParent, currentPath); + if (!currentNode.isPresent()) { + for (SchemaNodeBuilder un : currentParent.getUnknownNodes()) { + if (un.getQName().equals(currentPath)) { + currentNode = Optional.of(un); + } + } + } } return currentNode; } @@ -469,9 +481,8 @@ public final class BuilderUtils { return castOptional(SchemaNodeBuilder.class, findCaseInChoice((ChoiceBuilder) parent, child)); } else if (parent instanceof RpcDefinitionBuilder) { return castOptional(SchemaNodeBuilder.class, findContainerInRpc((RpcDefinitionBuilder) parent, child)); - } else { - LOG.trace("Child {} not found in node {}", child, parent); + LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent); return Optional.absent(); } } @@ -483,7 +494,7 @@ public final class BuilderUtils { * Class to be checked * @param optional * Original value - * @return + * @return Optional object with type argument casted as cls */ private static Optional castOptional(final Class cls, final Optional optional) { if (optional.isPresent()) { @@ -498,6 +509,7 @@ public final class BuilderUtils { return Optional.absent(); } + // FIXME: if rpc does not define input or output, this method creates it /** * * Gets input / output container from {@link RpcDefinitionBuilder} if QName @@ -511,13 +523,30 @@ public final class BuilderUtils { * @return Optional of input/output if defined and QName is input/output. * Otherwise {@link Optional#absent()}. */ - private static Optional findContainerInRpc(final RpcDefinitionBuilder parent, final QName child) { + private static Optional findContainerInRpc(final RpcDefinitionBuilder parent, + final QName child) { if (INPUT.equals(child.getLocalName())) { + if (parent.getInput() == null) { + QName qname = QName.create(parent.getQName().getModule(), INPUT); + final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(), + parent.getLine(), qname, parent.getPath().createChild(qname)); + inputBuilder.setParent(parent); + parent.setInput(inputBuilder); + return Optional.of(inputBuilder); + } return Optional.of(parent.getInput()); } else if (OUTPUT.equals(child.getLocalName())) { + if (parent.getOutput() == null) { + QName qname = QName.create(parent.getQName().getModule(), OUTPUT); + final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(), + parent.getLine(), qname, parent.getPath().createChild(qname)); + outputBuilder.setParent(parent); + parent.setOutput(outputBuilder); + return Optional.of(outputBuilder); + } return Optional.of(parent.getOutput()); } - LOG.trace("Child {} not found in node {}", child, parent); + LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent); return Optional.absent(); } @@ -538,7 +567,7 @@ public final class BuilderUtils { return Optional.of(caze); } } - LOG.trace("Child {} not found in node {}", child, parent); + LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent); return Optional.absent(); } @@ -559,7 +588,7 @@ public final class BuilderUtils { return Optional.of(childNode); } } - LOG.trace("Child {} not found in node {}", child, parent); + LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent); return Optional.absent(); } @@ -619,7 +648,7 @@ public final class BuilderUtils { return Optional. of(childNode); } } - LOG.trace("Child {} not found in node {}", child, builder); + LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, builder); return Optional.absent(); } @@ -627,18 +656,20 @@ public final class BuilderUtils { * Find augment target node and perform augmentation. * * @param augment + * augment builder to process * @param firstNodeParent * parent of first node in path - * @param path - * path to augment target * @return true if augmentation process succeed, false otherwise */ public static boolean processAugmentation(final AugmentationSchemaBuilder augment, final ModuleBuilder firstNodeParent) { - Optional potentialTargetNode = findSchemaNodeInModule(augment.getTargetNodeSchemaPath(), + Optional potentialTargetNode = findSchemaNodeInModule(augment.getTargetPath(), firstNodeParent); if (!potentialTargetNode.isPresent()) { return false; + } else if (potentialTargetNode.get() instanceof UnknownSchemaNodeBuilder) { + LOG.warn("Error in augment parsing: unsupported augment target: {}", potentialTargetNode.get()); + return true; } SchemaNodeBuilder targetNode = potentialTargetNode.get(); fillAugmentTarget(augment, targetNode); @@ -649,8 +680,8 @@ public final class BuilderUtils { return true; } - public static IdentitySchemaNodeBuilder findBaseIdentity(final Map> modules, - final ModuleBuilder module, final String baseString, final int line) { + public static IdentitySchemaNodeBuilder findBaseIdentity(final ModuleBuilder module, final String baseString, + final int line) { // FIXME: optimize indexOf() away? if (baseString.indexOf(':') != -1) { @@ -662,7 +693,7 @@ public final class BuilderUtils { throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString); } - ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, prefix, line); + ModuleBuilder dependentModule = getModuleByPrefix(module, prefix); if (dependentModule == null) { return null; } @@ -686,7 +717,7 @@ public final class BuilderUtils { /** * Get module in which this node is defined. * - * @param node + * @param node node * @return builder of module where this node is defined */ public static ModuleBuilder getParentModule(final Builder node) { @@ -697,7 +728,6 @@ public final class BuilderUtils { while (!(parent instanceof ModuleBuilder)) { parent = parent.getParent(); } - Preconditions.checkState(parent instanceof ModuleBuilder); ModuleBuilder parentModule = (ModuleBuilder) parent; if (parentModule.isSubmodule()) { parentModule = parentModule.getParent(); @@ -706,12 +736,11 @@ public final class BuilderUtils { } public static Set wrapChildNodes(final String moduleName, final int line, - final Set nodes, final SchemaPath parentPath, final URI ns, final Date rev, - final String pref) { - Set result = new HashSet<>(); + final Collection nodes, final SchemaPath parentPath, final QName parentQName) { + Set result = new LinkedHashSet<>(nodes.size()); for (DataSchemaNode node : nodes) { - QName qname = new QName(ns, rev, pref, node.getQName().getLocalName()); + QName qname = QName.create(parentQName, node.getQName().getLocalName()); DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname); result.add(wrapped); } @@ -724,19 +753,19 @@ public final class BuilderUtils { final SchemaPath schemaPath = parentPath.createChild(qname); if (node instanceof AnyXmlSchemaNode) { - return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node)); - } else if (node instanceof ChoiceNode) { - return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node)); + return new AnyXmlBuilder(moduleName, line, qname, schemaPath, (AnyXmlSchemaNode) node); + } else if (node instanceof ChoiceSchemaNode) { + return new ChoiceBuilder(moduleName, line, qname, schemaPath, (ChoiceSchemaNode) node); } else if (node instanceof ContainerSchemaNode) { - return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node)); + return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, (ContainerSchemaNode) node); } else if (node instanceof LeafSchemaNode) { - return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node)); + return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, (LeafSchemaNode) node); } else if (node instanceof LeafListSchemaNode) { - return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node)); + return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (LeafListSchemaNode) node); } else if (node instanceof ListSchemaNode) { - return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node)); + return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (ListSchemaNode) node); } else if (node instanceof ChoiceCaseNode) { - return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node)); + return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, (ChoiceCaseNode) node); } else { throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: " + node); @@ -744,11 +773,10 @@ public final class BuilderUtils { } public static Set wrapGroupings(final String moduleName, final int line, - final Set nodes, final SchemaPath parentPath, final URI ns, final Date rev, - final String pref) { + final Set nodes, final SchemaPath parentPath, final QName parentQName) { Set result = new HashSet<>(); for (GroupingDefinition node : nodes) { - QName qname = new QName(ns, rev, pref, node.getQName().getLocalName()); + QName qname = QName.create(parentQName, node.getQName().getLocalName()); SchemaPath schemaPath = parentPath.createChild(qname); result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node)); } @@ -756,24 +784,22 @@ public final class BuilderUtils { } public static Set wrapTypedefs(final String moduleName, final int line, - final DataNodeContainer dataNode, final SchemaPath parentPath, final URI ns, final Date rev, - final String pref) { + final DataNodeContainer dataNode, final SchemaPath parentPath, final QName parentQName) { Set> nodes = dataNode.getTypeDefinitions(); Set result = new HashSet<>(); for (TypeDefinition node : nodes) { - QName qname = new QName(ns, rev, pref, node.getQName().getLocalName()); + QName qname = QName.create(parentQName, node.getQName().getLocalName()); SchemaPath schemaPath = parentPath.createChild(qname); - result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node))); + result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, (ExtendedType) node)); } return result; } public static List wrapUnknownNodes(final String moduleName, final int line, - final List nodes, final SchemaPath parentPath, final URI ns, final Date rev, - final String pref) { + final List nodes, final SchemaPath parentPath, final QName parentQName) { List result = new ArrayList<>(); for (UnknownSchemaNode node : nodes) { - QName qname = new QName(ns, rev, pref, node.getQName().getLocalName()); + QName qname = QName.create(parentQName, node.getQName().getLocalName()); SchemaPath schemaPath = parentPath.createChild(qname); result.add(new UnknownSchemaNodeBuilderImpl(moduleName, line, qname, schemaPath, node)); } @@ -782,17 +808,148 @@ public final class BuilderUtils { private static final class ByteSourceImpl extends ByteSource { private final String toString; - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); + private final byte[] data; private ByteSourceImpl(final InputStream input) throws IOException { toString = input.toString(); - IOUtils.copy(input, output); + data = ByteStreams.toByteArray(input); } @Override public InputStream openStream() throws IOException { - return new NamedByteArrayInputStream(output.toByteArray(), toString); + return new NamedByteArrayInputStream(data, toString); + } + } + + public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) { + if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) { + return module; + } else { + return module.getImportedModule(prefix); + } + } + + public static ModuleBuilder findModule(final QName qname, final Map> modules) { + NavigableMap map = modules.get(qname.getNamespace()); + if (map == null) { + return null; + } + if (qname.getRevision() == null) { + return map.lastEntry().getValue(); + } + + final Entry lastEntry = map.lastEntry(); + if (qname.getRevision().compareTo(lastEntry.getKey()) > 0) { + /* + * We are trying to find more recent revision of module than is in + * the map. Most probably the yang models are not referenced + * correctly and the revision of a base module or submodule has not + * been updated along with revision of a referenced module or + * submodule. However, we should return the most recent entry in the + * map, otherwise the null pointer exception occurs (see Bug3799). + */ + LOG.warn(String + .format("Attempt to find more recent revision of module than is available. " + + "The requested revision is [%s], but the most recent available revision of module is [%s]." + + " Most probably some of Yang models do not have updated revision or they are not " + + "referenced correctly.", + qname.getRevision(), lastEntry.getKey())); + return lastEntry.getValue(); + } + + return map.get(qname.getRevision()); + } + + public static Map> createYangNamespaceContext( + final Collection modules, final Optional context) { + Map> namespaceContext = new HashMap<>(); + Set submodules = new HashSet<>(); + // first read ParseTree collection and separate modules and submodules + for (ParseTree module : modules) { + for (int i = 0; i < module.getChildCount(); i++) { + ParseTree moduleTree = module.getChild(i); + if (moduleTree instanceof Submodule_stmtContext) { + // put submodule context to separate collection + submodules.add((Submodule_stmtContext) moduleTree); + } else if (moduleTree instanceof Module_stmtContext) { + // get name, revision and namespace from module + Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree; + final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx); + Date rev = null; + URI namespace = null; + for (int j = 0; j < moduleCtx.getChildCount(); j++) { + ParseTree moduleCtxChildTree = moduleCtx.getChild(j); + if (moduleCtxChildTree instanceof Revision_stmtsContext) { + String revisionDateStr = YangModelDependencyInfo + .getLatestRevision((Revision_stmtsContext) moduleCtxChildTree); + if (revisionDateStr == null) { + rev = new Date(0); + } else { + rev = QName.parseRevision(revisionDateStr); + } + } + if (moduleCtxChildTree instanceof Module_header_stmtsContext) { + Module_header_stmtsContext headerCtx = (Module_header_stmtsContext) moduleCtxChildTree; + for (int k = 0; k < headerCtx.getChildCount(); k++) { + ParseTree ctx = headerCtx.getChild(k); + if (ctx instanceof Namespace_stmtContext) { + final String namespaceStr = ParserListenerUtils.stringFromNode(ctx); + namespace = URI.create(namespaceStr); + break; + } + } + } + } + // update namespaceContext + NavigableMap revToNs = namespaceContext.get(moduleName); + if (revToNs == null) { + revToNs = new TreeMap<>(); + revToNs.put(rev, namespace); + namespaceContext.put(moduleName, revToNs); + } + revToNs.put(rev, namespace); + } + } + } + // after all ParseTree-s are parsed update namespaceContext with modules + // from SchemaContext + if (context.isPresent()) { + for (Module module : context.get().getModules()) { + NavigableMap revToNs = namespaceContext.get(module.getName()); + if (revToNs == null) { + revToNs = new TreeMap<>(); + revToNs.put(module.getRevision(), module.getNamespace()); + namespaceContext.put(module.getName(), revToNs); + } + revToNs.put(module.getRevision(), module.getNamespace()); + } + } + // when all modules are processed, traverse submodules and update + // namespaceContext with mapping for submodules + for (Submodule_stmtContext submodule : submodules) { + final String moduleName = ParserListenerUtils.stringFromNode(submodule); + for (int i = 0; i < submodule.getChildCount(); i++) { + ParseTree subHeaderCtx = submodule.getChild(i); + if (subHeaderCtx instanceof Submodule_header_stmtsContext) { + for (int j = 0; j < subHeaderCtx.getChildCount(); j++) { + ParseTree belongsCtx = subHeaderCtx.getChild(j); + if (belongsCtx instanceof Belongs_to_stmtContext) { + final String belongsTo = ParserListenerUtils.stringFromNode(belongsCtx); + NavigableMap ns = namespaceContext.get(belongsTo); + if (ns == null) { + throw new YangParseException(moduleName, submodule.getStart().getLine(), String.format( + "Unresolved belongs-to statement: %s", belongsTo)); + } + // submodule get namespace and revision from module + NavigableMap subNs = new TreeMap<>(); + subNs.put(ns.firstKey(), ns.firstEntry().getValue()); + namespaceContext.put(moduleName, subNs); + } + } + } + } } + return namespaceContext; } }