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%2Fimpl%2FYangParserImpl.java;h=7448f130b2c3f615ab22d4e2f695b7ccc4bd1879;hb=ba1b7f529bb6d4c451500230504692478150454d;hp=54a4b62dd7f847022c1bb7c33c52de02cfe9895f;hpb=475f8732893197eb41bfa695a4c7dedb45f25f06;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java index 54a4b62dd7..7448f130b2 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java @@ -7,30 +7,30 @@ */ package org.opendaylight.yangtools.yang.parser.impl; -import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*; -import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveType; -import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnion; -import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnionWithContext; -import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeWithContext; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.*; - +import com.google.common.base.Preconditions; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.apache.commons.io.IOUtils; import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; +import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; +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.parser.api.YangModelParser; import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder; +import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.Builder; import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder; @@ -46,18 +46,59 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder.ModuleImpl; import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder; +import org.opendaylight.yangtools.yang.parser.util.Comparators; import org.opendaylight.yangtools.yang.parser.util.GroupingSort; import org.opendaylight.yangtools.yang.parser.util.GroupingUtils; import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort; +import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream; +import org.opendaylight.yangtools.yang.parser.util.NamedInputStream; import org.opendaylight.yangtools.yang.parser.util.ParserUtils; import org.opendaylight.yangtools.yang.parser.util.YangParseException; import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.fillAugmentTarget; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findBaseIdentity; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findBaseIdentityFromContext; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findModuleFromBuilders; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findModuleFromContext; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findSchemaNode; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.findSchemaNodeInModule; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.processAugmentation; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.setNodeAddedByUses; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.wrapChildNode; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.wrapChildNodes; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.wrapGroupings; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.wrapTypedefs; +import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.wrapUnknownNodes; +import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveType; +import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnion; +import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnionWithContext; +import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeWithContext; public final class YangParserImpl implements YangModelParser { @@ -73,7 +114,7 @@ public final class YangParserImpl implements YangModelParser { final String yangFileName = yangFile.getName(); final String[] fileList = directory.list(); - Preconditions.checkNotNull(fileList, directory + " not found"); + checkNotNull(fileList, directory + " not found"); FileInputStream yangFileStream = null; LinkedHashMap streamToFileMap = new LinkedHashMap<>(); @@ -98,17 +139,18 @@ public final class YangParserImpl implements YangModelParser { } } - Map parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()), + Map parsedBuilders = parseBuilders(new ArrayList<>(streamToFileMap.keySet()), new HashMap()); ModuleBuilder main = parsedBuilders.get(yangFileStream); List moduleBuilders = new ArrayList<>(); moduleBuilders.add(main); filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders); + Collection result = resolveSubmodules(moduleBuilders); // module builders sorted by dependencies - ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()]; - moduleBuilders.toArray(builders); + ModuleBuilder[] builders = new ModuleBuilder[result.size()]; + result.toArray(builders); List sortedBuilders = ModuleDependencySort.sort(builders); LinkedHashMap> modules = orderModules(sortedBuilders); Collection unsorted = build(modules).values(); @@ -195,6 +237,7 @@ public final class YangParserImpl implements YangModelParser { final Map inputStreams = new HashMap<>(); for (final File yangFile : yangFiles) { try { + inputStreams.put(new FileInputStream(yangFile), yangFile); } catch (FileNotFoundException e) { LOG.warn("Exception while reading yang file: " + yangFile.getName(), e); @@ -224,33 +267,95 @@ public final class YangParserImpl implements YangModelParser { return result; } + // TODO: fix exception handling @Override public Map parseYangModelsFromStreamsMapped(final List yangModelStreams) { if (yangModelStreams == null) { return Collections.emptyMap(); } - Map builderToStreamMap = new HashMap<>(); - Map> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap, + + // copy input streams so that they can be read more than once + Map arrayBackedToOriginalInputStreams = new HashMap<>(); + for (final InputStream originalIS : yangModelStreams) { + InputStream arrayBackedIs; + try { + arrayBackedIs = NamedByteArrayInputStream.create(originalIS); + } catch (IOException e) { + // FIXME: throw IOException here + throw new IllegalStateException("Can not get yang as String from " + originalIS, e); + } + arrayBackedToOriginalInputStreams.put(arrayBackedIs, originalIS); + } + + // it would be better if all code from here used string representation of yang sources instead of input streams + Map builderToStreamMap = new HashMap<>(); // FIXME: do not modify input parameter + Map> modules = resolveModuleBuilders(new ArrayList<>(arrayBackedToOriginalInputStreams.keySet()), + builderToStreamMap, null); - Map result = new LinkedHashMap<>(); + + + // TODO move deeper + for(TreeMap value : modules.values()) { + Collection values = value.values(); + for(ModuleBuilder builder: values) { + InputStream is = builderToStreamMap.get(builder); + try { + is.reset(); + } catch (IOException e) { + // this cannot happen because it is ByteArrayInputStream + throw new IllegalStateException("Possible error in code", e); + } + String content; + try { + content = IOUtils.toString(is); + } catch (IOException e) { + // this cannot happen because it is ByteArrayInputStream + throw new IllegalStateException("Possible error in code", e); + } + builder.setSource(content); + } + } + + Map builderToModuleMap = build(modules); + Set keyset = builderToModuleMap.keySet(); List sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()])); + Map result = new LinkedHashMap<>(); for (ModuleBuilder key : sorted) { - result.put(builderToStreamMap.get(key), builderToModuleMap.get(key)); + Module value = checkNotNull(builderToModuleMap.get(key), "Cannot get module for %s", key); + InputStream arrayBackedIS = checkNotNull(builderToStreamMap.get(key), "Cannot get is for %s", key); + InputStream originalIS = arrayBackedToOriginalInputStreams.get(arrayBackedIS); + result.put(originalIS, value); } return result; } @Override public SchemaContext resolveSchemaContext(final Set modules) { - return new SchemaContextImpl(modules); + // after merging parse method with this one, add support for getting submodule sources. + Map identifiersToSources = new HashMap<>(); + for(Module module: modules) { + ModuleImpl moduleImpl = (ModuleImpl) module; + identifiersToSources.put(module, moduleImpl.getSource()); + } + return new SchemaContextImpl(modules, identifiersToSources); } + // FIXME: why a list is required? + // FIXME: streamToBuilderMap is output of this method, not input private Map parseModuleBuilders(List inputStreams, Map streamToBuilderMap) { + Map modules = parseBuilders(inputStreams, streamToBuilderMap); + Map result = resolveSubmodules(modules); + return result; + } + // FIXME: why a list is required? + // FIXME: streamToBuilderMap is output of this method, not input + private Map parseBuilders(List inputStreams, + Map streamToBuilderMap) { final ParseTreeWalker walker = new ParseTreeWalker(); final Map trees = parseStreams(inputStreams); final Map builders = new LinkedHashMap<>(); @@ -260,18 +365,104 @@ public final class YangParserImpl implements YangModelParser { YangParserListenerImpl yangModelParser; for (Map.Entry entry : trees.entrySet()) { - yangModelParser = new YangParserListenerImpl(); + InputStream is = entry.getKey(); + String path = null; + if (is instanceof NamedInputStream) { + path = is.toString(); + } + yangModelParser = new YangParserListenerImpl(path); walker.walk(yangModelParser, entry.getValue()); ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder(); // We expect the order of trees and streams has to be the same + // FIXME: input parameters should be treated as immutable streamToBuilderMap.put(moduleBuilder, entry.getKey()); + builders.put(entry.getKey(), moduleBuilder); } return builders; } + private Map resolveSubmodules(Map builders) { + Map modules = new HashMap<>(); + Set submodules = new HashSet<>(); + for (Map.Entry entry : builders.entrySet()) { + ModuleBuilder moduleBuilder = entry.getValue(); + if (moduleBuilder.isSubmodule()) { + submodules.add(moduleBuilder); + } else { + modules.put(entry.getKey(), moduleBuilder); + } + } + + Collection values = modules.values(); + for (ModuleBuilder submodule : submodules) { + for (ModuleBuilder module : values) { + if (module.getName().equals(submodule.getBelongsTo())) { + addSubmoduleToModule(submodule, module); + } + } + } + return modules; + } + + private Collection resolveSubmodules(Collection builders) { + Collection modules = new HashSet<>(); + Set submodules = new HashSet<>(); + for (ModuleBuilder moduleBuilder : builders) { + if (moduleBuilder.isSubmodule()) { + submodules.add(moduleBuilder); + } else { + modules.add(moduleBuilder); + } + } + + for (ModuleBuilder submodule : submodules) { + for (ModuleBuilder module : modules) { + if (module.getName().equals(submodule.getBelongsTo())) { + addSubmoduleToModule(submodule, module); + } + } + } + return modules; + } + + private void addSubmoduleToModule(ModuleBuilder submodule, ModuleBuilder module) { + submodule.setParent(module); + module.getDirtyNodes().addAll(submodule.getDirtyNodes()); + module.getModuleImports().addAll(submodule.getModuleImports()); + module.getAugments().addAll(submodule.getAugments()); + module.getAugmentBuilders().addAll(submodule.getAugmentBuilders()); + module.getAllAugments().addAll(submodule.getAllAugments()); + module.getChildNodeBuilders().addAll(submodule.getChildNodeBuilders()); + module.getChildNodes().addAll(submodule.getChildNodes()); + module.getGroupings().addAll(submodule.getGroupings()); + module.getGroupingBuilders().addAll(submodule.getGroupingBuilders()); + module.getTypeDefinitions().addAll(submodule.getTypeDefinitions()); + module.getTypeDefinitionBuilders().addAll(submodule.getTypeDefinitionBuilders()); + module.getUsesNodes().addAll(submodule.getUsesNodes()); + module.getUsesNodeBuilders().addAll(submodule.getUsesNodeBuilders()); + module.getAllGroupings().addAll(submodule.getAllGroupings()); + module.getAllUsesNodes().addAll(submodule.getAllUsesNodes()); + module.getRpcs().addAll(submodule.getRpcs()); + module.getAddedRpcs().addAll(submodule.getAddedRpcs()); + module.getNotifications().addAll(submodule.getNotifications()); + module.getAddedNotifications().addAll(submodule.getAddedNotifications()); + module.getIdentities().addAll(submodule.getIdentities()); + module.getAddedIdentities().addAll(submodule.getAddedIdentities()); + module.getFeatures().addAll(submodule.getFeatures()); + module.getAddedFeatures().addAll(submodule.getAddedFeatures()); + module.getDeviations().addAll(submodule.getDeviations()); + module.getDeviationBuilders().addAll(submodule.getDeviationBuilders()); + module.getExtensions().addAll(submodule.getExtensions()); + module.getAddedExtensions().addAll(submodule.getAddedExtensions()); + module.getUnknownNodes().addAll(submodule.getUnknownNodes()); + module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes()); + } + + // FIXME: why a list is required? + // FIXME: streamToBuilderMap is output of this method, not input private Map> resolveModuleBuilders(final List yangFileStreams, final Map streamToBuilderMap, final SchemaContext context) { Map parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap); @@ -317,7 +508,22 @@ public final class YangParserImpl implements YangModelParser { } private void filterImports(ModuleBuilder main, List other, List filtered) { - for (ModuleImport mi : main.getModuleImports()) { + Set imports = main.getModuleImports(); + + // if this is submodule, add parent to filtered and pick its imports + if (main.isSubmodule()) { + TreeMap dependencies = new TreeMap<>(); + for (ModuleBuilder mb : other) { + if (mb.getName().equals(main.getBelongsTo())) { + dependencies.put(mb.getRevision(), mb); + } + } + ModuleBuilder parent = dependencies.get(dependencies.firstKey()); + filtered.add(parent); + imports.addAll(parent.getModuleImports()); + } + + for (ModuleImport mi : imports) { for (ModuleBuilder builder : other) { if (mi.getModuleName().equals(builder.getModuleName())) { if (mi.getRevision() == null) { @@ -338,6 +544,7 @@ public final class YangParserImpl implements YangModelParser { } } + // FIXME: why a list is required? private Map parseStreams(final List yangStreams) { final Map trees = new HashMap<>(); for (InputStream yangStream : yangStreams) { @@ -358,14 +565,50 @@ public final class YangParserImpl implements YangModelParser { parser.addErrorListener(errorListener); result = parser.yang(); errorListener.validate(); + } catch (IOException e) { + // TODO: fix this ASAP + LOG.warn("Exception while reading yang file: " + yangStream, e); + } + return result; + } + + public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) { + YangContext result = null; + try { + final ANTLRInputStream input = new ANTLRInputStream(yangStream); + final YangLexer lexer = new YangLexer(input); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + final YangParser parser = new YangParser(tokens); + parser.removeErrorListeners(); + result = parser.yang(); } catch (IOException e) { LOG.warn("Exception while reading yang file: " + yangStream, e); } return result; } + /** + * Creates builder-to-module map based on given modules. Method first + * resolve unresolved type references, instantiate groupings through uses + * statements and perform augmentation. + * + * Node resolving must be performed in following order: + *
    + *
  1. + * unresolved type references
  2. + *
  3. + * uses in groupings
  4. + *
  5. + * uses in other nodes
  6. + *
  7. + * augments
  8. + *
+ * + * @param modules + * all loaded modules + * @return modules mapped on their builders + */ private Map build(final Map> modules) { - // fix unresolved nodes resolveDirtyNodes(modules); resolveAugmentsTargetPath(modules, null); resolveUsesTargetGrouping(modules, null); @@ -386,9 +629,31 @@ public final class YangParserImpl implements YangModelParser { return result; } + /** + * Creates builder-to-module map based on given modules. Method first + * resolve unresolved type references, instantiate groupings through uses + * statements and perform augmentation. + * + * Node resolving must be performed in following order: + *
    + *
  1. + * unresolved type references
  2. + *
  3. + * uses in groupings
  4. + *
  5. + * uses in other nodes
  6. + *
  7. + * augments
  8. + *
+ * + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + * @return modules mapped on their builders + */ private Map buildWithContext(final Map> modules, final SchemaContext context) { - // fix unresolved nodes resolvedDirtyNodesWithContext(modules, context); resolveAugmentsTargetPath(modules, context); resolveUsesTargetGrouping(modules, context); @@ -409,6 +674,12 @@ public final class YangParserImpl implements YangModelParser { return result; } + /** + * Resolve all unresolved type references. + * + * @param modules + * all loaded modules + */ private void resolveDirtyNodes(final Map> modules) { for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry childEntry : entry.getValue().entrySet()) { @@ -420,6 +691,14 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Resolve all unresolved type references. + * + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ private void resolvedDirtyNodesWithContext(final Map> modules, final SchemaContext context) { for (Map.Entry> entry : modules.entrySet()) { @@ -488,10 +767,13 @@ public final class YangParserImpl implements YangModelParser { } /** - * Correct augment target path. + * Traverse through augmentations of modules and fix their child nodes + * schema path. * * @param modules * all loaded modules + * @param context + * SchemaContext containing already resolved modules */ private void resolveAugmentsTargetPath(final Map> modules, SchemaContext context) { @@ -508,6 +790,16 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Find augment target and set correct schema path for all its child nodes. + * + * @param modules + * all loaded modules + * @param augment + * augment to resolve + * @param context + * SchemaContext containing already resolved modules + */ private void setCorrectAugmentTargetPath(final Map> modules, final AugmentationSchemaBuilder augment, final SchemaContext context) { ModuleBuilder module = ParserUtils.getParentModule(augment); @@ -539,11 +831,9 @@ public final class YangParserImpl implements YangModelParser { newPath.add(new QName(ns, revision, prefix, qn.getLocalName())); } } else { - for (QName qn : oldPath) { URI ns = module.getNamespace(); Date rev = module.getRevision(); - String pref = module.getPrefix(); String localPrefix = qn.getPrefix(); if (localPrefix != null && !("".equals(localPrefix))) { ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix, @@ -556,28 +846,35 @@ public final class YangParserImpl implements YangModelParser { } ns = m.getNamespace(); rev = m.getRevision(); - pref = m.getPrefix(); } else { ns = currentModule.getNamespace(); rev = currentModule.getRevision(); - pref = currentModule.getPrefix(); } } - newPath.add(new QName(ns, rev, pref, qn.getLocalName())); + newPath.add(new QName(ns, rev, localPrefix, qn.getLocalName())); } } - augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute())); + augment.setTargetNodeSchemaPath(new SchemaPath(newPath, true)); - for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath()); } } + /** + * Set new schema path to node and all its child nodes based on given parent + * path. This method do not change the namespace. + * + * @param node + * node which schema path should be updated + * @param parentPath + * schema path of parent node + */ private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) { SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName()); node.setPath(newPath); if (node instanceof DataNodeContainerBuilder) { - for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodes()) { + for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) { correctPathForAugmentNodes(child, node.getPath()); } } @@ -606,7 +903,7 @@ public final class YangParserImpl implements YangModelParser { continue; } - for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { if (childNode.getConstraints().isMandatory()) { throw new YangParseException(augment.getModuleName(), augment.getLine(), "Error in augment parsing: cannot augment mandatory node " @@ -617,9 +914,7 @@ public final class YangParserImpl implements YangModelParser { } /** - * Go through all augment definitions and resolve them. This method works in - * same way as {@link #resolveAugments(Map)} except that if target node is - * not found in loaded modules, it search for target node in given context. + * Go through all augment definitions and resolve them. * * @param modules * all loaded modules @@ -641,18 +936,17 @@ public final class YangParserImpl implements YangModelParser { sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()])); } - // resolve other augments for (ModuleBuilder mb : sorted) { if (mb != null) { List augments = mb.getAllAugments(); checkAugmentMandatoryNodes(augments); + Collections.sort(augments, Comparators.AUGMENT_COMP); for (AugmentationSchemaBuilder augment : augments) { if (!(augment.isResolved())) { boolean resolved = resolveAugment(augment, mb, modules, context); if (!resolved) { throw new YangParseException(augment.getModuleName(), augment.getLine(), "Error in augment parsing: failed to find augment target: " + augment); - } } } @@ -660,6 +954,19 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Perform augmentation defined under uses statement. + * + * @param augment + * augment to resolve + * @param module + * current module + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + * @return true if augment process succeed + */ private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, final Map> modules, final SchemaContext context) { if (augment.isResolved()) { @@ -670,16 +977,35 @@ public final class YangParserImpl implements YangModelParser { DataNodeContainerBuilder parentNode = usesNode.getParent(); SchemaNodeBuilder targetNode; if (parentNode instanceof ModuleBuilder) { - targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder)parentNode); + targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder) parentNode); } else { - targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder)parentNode); + targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder) parentNode); } - fillAugmentTarget(augment, targetNode); - augment.setResolved(true); - return true; + if (targetNode instanceof AugmentationTargetBuilder) { + fillAugmentTarget(augment, targetNode); + ((AugmentationTargetBuilder) targetNode).addAugmentation(augment); + augment.setResolved(true); + return true; + } else { + throw new YangParseException(module.getName(), augment.getLine(), + "Failed to resolve augment in uses. Invalid augment target: " + targetNode); + } } + /** + * Find augment target module and perform augmentation. + * + * @param augment + * augment to resolve + * @param module + * current module + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + * @return true if augment process succeed + */ private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, final Map> modules, final SchemaContext context) { if (augment.isResolved()) { @@ -749,7 +1075,7 @@ public final class YangParserImpl implements YangModelParser { * module being resolved */ private void resolveIdentities(final Map> modules, final ModuleBuilder module) { - final Set identities = module.getIdentities(); + final Set identities = module.getAddedIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { final String baseIdentityName = identity.getBaseIdentityName(); final int line = identity.getLine(); @@ -778,7 +1104,7 @@ public final class YangParserImpl implements YangModelParser { */ private void resolveIdentitiesWithContext(final Map> modules, final ModuleBuilder module, final SchemaContext context) { - final Set identities = module.getIdentities(); + final Set identities = module.getAddedIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { final String baseIdentityName = identity.getBaseIdentityName(); final int line = identity.getLine(); @@ -831,6 +1157,14 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Resolve uses statements defined in groupings. + * + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ private void resolveUsesForGroupings(final Map> modules, final SchemaContext context) { final Set allGroupings = new HashSet<>(); for (Map.Entry> entry : modules.entrySet()) { @@ -849,6 +1183,14 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Resolve uses statements. + * + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ private void resolveUsesForNodes(final Map> modules, final SchemaContext context) { for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { @@ -862,6 +1204,17 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Find target grouping and copy its child nodes to current location with + * new namespace. + * + * @param usesNode + * uses node to resolve + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ private void resolveUses(UsesNodeBuilder usesNode, final Map> modules, final SchemaContext context) { if (!usesNode.isResolved()) { @@ -875,7 +1228,7 @@ public final class YangParserImpl implements YangModelParser { resolveUsesAugment(augment, module, modules, context); } } else { - parent.getChildNodes().addAll(target.instantiateChildNodes(parent)); + parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent)); parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent)); parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent)); parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); @@ -888,6 +1241,17 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Copy target grouping child nodes to current location with + * new namespace. + * + * @param usesNode + * uses node to resolve + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ private void resolveUsesWithContext(UsesNodeBuilder usesNode) { final int line = usesNode.getLine(); DataNodeContainerBuilder parent = usesNode.getParent(); @@ -916,7 +1280,7 @@ public final class YangParserImpl implements YangModelParser { Set childNodes = wrapChildNodes(module.getModuleName(), line, gd.getChildNodes(), parentPath, ns, rev, pref); - parent.getChildNodes().addAll(childNodes); + parent.getChildNodeBuilders().addAll(childNodes); for (DataSchemaNodeBuilder childNode : childNodes) { setNodeAddedByUses(childNode); } @@ -943,13 +1307,22 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Try to find extension builder describing this unknown node and assign it + * to unknown node builder. + * + * @param modules + * all loaded modules + * @param module + * current module + */ private void resolveUnknownNodes(final Map> modules, final ModuleBuilder module) { for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) { QName nodeType = usnb.getNodeType(); try { ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(), usnb.getLine()); - for (ExtensionBuilder extension : dependentModule.getExtensions()) { + for (ExtensionBuilder extension : dependentModule.getAddedExtensions()) { if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { usnb.setNodeType(extension.getQName()); usnb.setExtensionBuilder(extension); @@ -963,6 +1336,18 @@ public final class YangParserImpl implements YangModelParser { } } + /** + * Try to find extension builder describing this unknown node and assign it + * to unknown node builder. If extension is not found in loaded modules, try + * to find it in context. + * + * @param modules + * all loaded modules + * @param module + * current module + * @param context + * SchemaContext containing already resolved modules + */ private void resolveUnknownNodesWithContext(final Map> modules, final ModuleBuilder module, final SchemaContext context) { for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) { @@ -983,7 +1368,7 @@ public final class YangParserImpl implements YangModelParser { } } } else { - for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) { + for (ExtensionBuilder extension : dependentModuleBuilder.getAddedExtensions()) { if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { usnb.setExtensionBuilder(extension); break; @@ -1023,7 +1408,7 @@ public final class YangParserImpl implements YangModelParser { * module in which resolve deviations */ private void resolveDeviation(final Map> modules, final ModuleBuilder module) { - for (DeviationBuilder dev : module.getDeviations()) { + for (DeviationBuilder dev : module.getDeviationBuilders()) { int line = dev.getLine(); SchemaPath targetPath = dev.getTargetPath(); List path = targetPath.getPath(); @@ -1070,7 +1455,7 @@ public final class YangParserImpl implements YangModelParser { */ private void resolveDeviationWithContext(final Map> modules, final ModuleBuilder module, final SchemaContext context) { - for (DeviationBuilder dev : module.getDeviations()) { + for (DeviationBuilder dev : module.getDeviationBuilders()) { int line = dev.getLine(); SchemaPath targetPath = dev.getTargetPath(); List path = targetPath.getPath();