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=cae36920d3193b708af3830db0665a6222220860;hp=6c22971d7ea3a82073ee325c5d9fba48060cc4ff;hpb=7923a034c0bf40777939bb27bc90e3a2a2ac1b37;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 6c22971d7e..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,47 +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.*; - -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.Map.Entry; -import java.util.Set; -import java.util.TreeMap; - +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.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; @@ -56,26 +39,67 @@ import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder; 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 com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +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 { private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class); @@ -90,11 +114,10 @@ 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<>(); - try { yangFileStream = new FileInputStream(yangFile); streamToFileMap.put(yangFileStream, yangFile); @@ -116,136 +139,223 @@ 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); - - ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()]; - moduleBuilders.toArray(builders); - - // module dependency graph sorted - List sorted = ModuleDependencySort.sort(builders); - - final LinkedHashMap> modules = orderModules(sorted); - return new LinkedHashSet<>(build(modules).values()); + Collection result = resolveSubmodules(moduleBuilders); + + // module builders sorted by dependencies + ModuleBuilder[] builders = new ModuleBuilder[result.size()]; + result.toArray(builders); + List sortedBuilders = ModuleDependencySort.sort(builders); + LinkedHashMap> modules = orderModules(sortedBuilders); + Collection unsorted = build(modules).values(); + return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); } @Override public Set parseYangModels(final List yangFiles) { - return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values()); + Collection unsorted = parseYangModelsMapped(yangFiles).values(); + return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); } @Override public Set parseYangModels(final List yangFiles, final SchemaContext context) { - if (yangFiles != null) { - final Map inputStreams = Maps.newHashMap(); + if (yangFiles == null) { + return Collections.emptySet(); + } - 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); - } + 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); } + } - Map builderToStreamMap = Maps.newHashMap(); - final Map> modules = resolveModuleBuilders( - Lists.newArrayList(inputStreams.keySet()), builderToStreamMap); + List yangModelStreams = new ArrayList<>(inputStreams.keySet()); + Map builderToStreamMap = new HashMap<>(); + Map> modules = resolveModuleBuilders(yangModelStreams, + builderToStreamMap, null); - for (InputStream is : inputStreams.keySet()) { - try { - is.close(); - } catch (IOException e) { - LOG.debug("Failed to close stream."); - } + for (InputStream is : inputStreams.keySet()) { + try { + is.close(); + } catch (IOException e) { + LOG.debug("Failed to close stream."); } + } - return new LinkedHashSet<>(buildWithContext(modules, context).values()); + final Collection unsorted = buildWithContext(modules, context).values(); + if (context != null) { + for (Module m : context.getModules()) { + if (!unsorted.contains(m)) { + unsorted.add(m); + } + } } - return Collections.emptySet(); + return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); } @Override public Set parseYangModelsFromStreams(final List yangModelStreams) { - return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values()); + Collection unsorted = parseYangModelsFromStreamsMapped(yangModelStreams).values(); + return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); } @Override public Set parseYangModelsFromStreams(final List yangModelStreams, SchemaContext context) { - if (yangModelStreams != null) { - Map builderToStreamMap = Maps.newHashMap(); - final Map> modules = resolveModuleBuildersWithContext( - yangModelStreams, builderToStreamMap, context); - return new LinkedHashSet<>(buildWithContext(modules, context).values()); + if (yangModelStreams == null) { + return Collections.emptySet(); + } + + final Map builderToStreamMap = new HashMap<>(); + final Map> modules = resolveModuleBuilders(yangModelStreams, + builderToStreamMap, context); + final Set unsorted = new LinkedHashSet<>(buildWithContext(modules, context).values()); + if (context != null) { + for (Module m : context.getModules()) { + if (!unsorted.contains(m)) { + unsorted.add(m); + } + } } - return Collections.emptySet(); + return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); } @Override public Map parseYangModelsMapped(List yangFiles) { - if (yangFiles != null) { - final Map inputStreams = Maps.newHashMap(); - - 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); - } - } + if (yangFiles == null) { + return Collections.emptyMap(); + } - Map builderToStreamMap = Maps.newHashMap(); - final Map> modules = resolveModuleBuilders( - Lists.newArrayList(inputStreams.keySet()), builderToStreamMap); + final Map inputStreams = new HashMap<>(); + for (final File yangFile : yangFiles) { + try { - for (InputStream is : inputStreams.keySet()) { - try { - is.close(); - } catch (IOException e) { - LOG.debug("Failed to close stream."); - } + inputStreams.put(new FileInputStream(yangFile), yangFile); + } catch (FileNotFoundException e) { + LOG.warn("Exception while reading yang file: " + yangFile.getName(), e); } + } - Map retVal = Maps.newLinkedHashMap(); - Map builderToModuleMap = build(modules); + List yangModelStreams = new ArrayList<>(inputStreams.keySet()); + Map builderToStreamMap = new HashMap<>(); + Map> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap, + null); - for (Entry builderToModule : builderToModuleMap.entrySet()) { - retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())), - builderToModule.getValue()); + for (InputStream is : inputStreams.keySet()) { + try { + is.close(); + } catch (IOException e) { + LOG.debug("Failed to close stream."); } + } - return retVal; + Map result = new LinkedHashMap<>(); + Map builderToModuleMap = build(modules); + Set keyset = builderToModuleMap.keySet(); + List sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()])); + for (ModuleBuilder key : sorted) { + result.put(inputStreams.get(builderToStreamMap.get(key)), builderToModuleMap.get(key)); } - return Collections.emptyMap(); + return result; } + // TODO: fix exception handling @Override public Map parseYangModelsFromStreamsMapped(final List yangModelStreams) { - Map builderToStreamMap = Maps.newHashMap(); + if (yangModelStreams == null) { + return Collections.emptyMap(); + } + + + // 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); + + + // 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); + } + } + - final Map> modules = resolveModuleBuilders(yangModelStreams, - builderToStreamMap); - Map retVal = Maps.newLinkedHashMap(); Map builderToModuleMap = build(modules); - for (Entry builderToModule : builderToModuleMap.entrySet()) { - retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue()); + Set keyset = builderToModuleMap.keySet(); + List sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()])); + Map result = new LinkedHashMap<>(); + for (ModuleBuilder key : sorted) { + 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 retVal; + 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<>(); @@ -255,26 +365,106 @@ 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> resolveModuleBuilders(final List yangFileStreams, - Map streamToBuilderMap) { - return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null); + 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 Map> resolveModuleBuildersWithContext( - final List yangFileStreams, final Map streamToBuilderMap, - final SchemaContext context) { + 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); ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()]; parsedBuilders.values().toArray(builders); @@ -286,7 +476,6 @@ public final class YangParserImpl implements YangModelParser { } else { sorted = ModuleDependencySort.sortWithContext(context, builders); } - return orderModules(sorted); } @@ -298,8 +487,7 @@ public final class YangParserImpl implements YangModelParser { * @return modules ordered by name and revision */ private LinkedHashMap> orderModules(List modules) { - // LinkedHashMap must be used to preserve order - LinkedHashMap> result = new LinkedHashMap<>(); + final LinkedHashMap> result = new LinkedHashMap<>(); for (final ModuleBuilder builder : modules) { if (builder == null) { continue; @@ -320,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) { @@ -341,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) { @@ -362,19 +566,55 @@ public final class YangParserImpl implements YangModelParser { 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); resolveUsesForGroupings(modules, null); resolveUsesForNodes(modules, null); - resolveAugments(modules); + resolveAugments(modules, null); resolveDeviations(modules); // build @@ -389,15 +629,37 @@ 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); resolveUsesForGroupings(modules, context); resolveUsesForNodes(modules, context); - resolveAugmentsWithContext(modules, context); + resolveAugments(modules, context); resolveDeviationsWithContext(modules, context); // build @@ -412,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()) { @@ -423,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()) { @@ -460,7 +736,7 @@ public final class YangParserImpl implements YangModelParser { throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity"); } idref.setBaseIdentity(identity); - nodeToResolve.setType(idref.build(null)); + nodeToResolve.setType(idref.build()); } else { resolveType(nodeToResolve, modules, module); } @@ -482,7 +758,7 @@ public final class YangParserImpl implements YangModelParser { IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(), idref.getLine()); idref.setBaseIdentity(identity); - nodeToResolve.setType(idref.build(null)); + nodeToResolve.setType(idref.build()); } else { resolveTypeWithContext(nodeToResolve, modules, module, context); } @@ -491,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) { @@ -511,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); @@ -542,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, @@ -559,73 +846,41 @@ 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.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) { - node.setPath(ParserUtils.createSchemaPath(parentPath, node.getQName())); + SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName()); + node.setPath(newPath); if (node instanceof DataNodeContainerBuilder) { for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) { correctPathForAugmentNodes(child, node.getPath()); } } - } - - /** - * Go through all augment definitions and perform augmentation. It is - * expected that modules are already sorted by their dependencies. - * - * @param modules - * all loaded modules - */ - private void resolveAugments(final Map> modules) { - // collect augments from all loaded modules - final List allAugments = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - allAugments.addAll(inner.getValue().getAllAugments()); - } - } - - checkAugmentMandatoryNodes(allAugments); - - for (int i = 0; i < allAugments.size(); i++) { - // pick one augment - final AugmentationSchemaBuilder augment = allAugments.get(i); - // create collection of others - List others = new ArrayList<>(allAugments); - others.remove(augment); - - // try to resolve it - boolean resolved = resolveAugment(modules, augment); - // while not resolved - int j = 0; - while (!(resolved) && j < others.size()) { - // try to resolve next augment - resolveAugment(modules, others.get(j)); - // then try to resolve first again - resolved = resolveAugment(modules, augment); - j++; - - } - - if (!resolved) { - throw new YangParseException(augment.getModuleName(), augment.getLine(), - "Error in augment parsing: failed to find augment target"); + if (node instanceof ChoiceBuilder) { + for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) { + correctPathForAugmentNodes(child, node.getPath()); } } } @@ -659,130 +914,155 @@ public final class YangParserImpl implements YangModelParser { } /** - * Search for augment target and perform augmentation. + * Go through all augment definitions and resolve them. * * @param modules * all loaded modules - * @param augment - * augment to resolve - * @return true if target node found, false otherwise + * @param context + * SchemaContext containing already resolved modules */ - private boolean resolveAugment(final Map> modules, - final AugmentationSchemaBuilder augment) { - if (augment.isResolved()) { - return true; + private void resolveAugments(final Map> modules, final SchemaContext context) { + List all = new ArrayList<>(); + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { + all.add(inner.getValue()); + } } - int line = augment.getLine(); - ModuleBuilder module = getParentModule(augment); - List path = augment.getTargetPath().getPath(); - Builder augmentParent = augment.getParent(); - - Builder firstNodeParent; - if (augmentParent instanceof ModuleBuilder) { - // if augment is defined under module, parent of first node is - // target module - final QName firstNameInPath = path.get(0); - String prefix = firstNameInPath.getPrefix(); - if (prefix == null) { - prefix = module.getPrefix(); - } - firstNodeParent = findModuleFromBuilders(modules, module, prefix, line); - } else if (augmentParent instanceof UsesNodeBuilder) { - firstNodeParent = augmentParent.getParent(); + List sorted; + if (context == null) { + sorted = ModuleDependencySort.sort(all.toArray(new ModuleBuilder[all.size()])); } else { - // augment can be defined only under module or uses - throw new YangParseException(augment.getModuleName(), line, - "Failed to parse augment: Unresolved parent of augment: " + augmentParent); + sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()])); } - return processAugmentation(augment, firstNodeParent); + 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); + } + } + } + } + } } /** - * 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. + * 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 void resolveAugmentsWithContext(final Map> modules, - final SchemaContext context) { - // collect augments from all loaded modules - final List allAugments = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - allAugments.addAll(inner.getValue().getAllAugments()); - } + private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, + final Map> modules, final SchemaContext context) { + if (augment.isResolved()) { + return true; } - for (int i = 0; i < allAugments.size(); i++) { - // pick augment from list - final AugmentationSchemaBuilder augment = allAugments.get(i); - // try to resolve it - boolean resolved = resolveAugmentWithContext(modules, augment, context); - // while not resolved - int j = i + 1; - while (!(resolved) && j < allAugments.size()) { - // try to resolve next augment - resolveAugmentWithContext(modules, allAugments.get(j), context); - // then try to resolve first again - resolved = resolveAugmentWithContext(modules, augment, context); - j++; - } + UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent(); + DataNodeContainerBuilder parentNode = usesNode.getParent(); + SchemaNodeBuilder targetNode; + if (parentNode instanceof ModuleBuilder) { + targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder) parentNode); + } else { + targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder) parentNode); + } - if (!resolved) { - throw new YangParseException(augment.getModuleName(), augment.getLine(), - "Error in augment parsing: failed to find augment target"); - } + 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); } } /** - * Search for augment target and perform augmentation. + * Find augment target module and perform augmentation. * - * @param modules - * all loaded modules * @param augment * augment to resolve + * @param module + * current module + * @param modules + * all loaded modules * @param context * SchemaContext containing already resolved modules - * @return true if target node found, false otherwise + * @return true if augment process succeed */ - private boolean resolveAugmentWithContext(final Map> modules, - final AugmentationSchemaBuilder augment, final SchemaContext context) { + private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, + final Map> modules, final SchemaContext context) { if (augment.isResolved()) { return true; } - int line = augment.getLine(); - ModuleBuilder module = getParentModule(augment); - List path = augment.getTargetNodeSchemaPath().getPath(); - final QName firstNameInPath = path.get(0); - String prefix = firstNameInPath.getPrefix(); - if (prefix == null) { - prefix = module.getPrefix(); - } - Builder augmentParent = augment.getParent(); - Builder currentParent; - if (augmentParent instanceof ModuleBuilder) { - // if augment is defined under module, first parent is target module - currentParent = findModuleFromBuilders(modules, module, prefix, line); - } else if (augmentParent instanceof UsesNodeBuilder) { - currentParent = augmentParent.getParent(); - } else { - // augment can be defined only under module or uses - throw new YangParseException(augment.getModuleName(), augment.getLine(), - "Error in augment parsing: Unresolved parent of augment: " + augmentParent); + + List targetPath = augment.getTargetPath().getPath(); + ModuleBuilder targetModule = findTargetModule(targetPath.get(0), module, modules, context, augment.getLine()); + if (targetModule == null) { + throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment " + + augment); } - if (currentParent == null) { - return processAugmentationOnContext(augment, path, module, prefix, context); + return processAugmentation(augment, targetModule); + } + + /** + * Find module from loaded modules or from context based on given qname. If + * module is found in context, create wrapper over this module and add it to + * collection of loaded modules. + * + * @param qname + * @param module + * current module + * @param modules + * all loaded modules + * @param context + * schema context + * @param line + * current line + * @return + */ + private ModuleBuilder findTargetModule(final QName qname, final ModuleBuilder module, + final Map> modules, final SchemaContext context, final int line) { + ModuleBuilder targetModule = null; + + String prefix = qname.getPrefix(); + if (prefix == null || prefix.equals("")) { + targetModule = module; } else { - return processAugmentation(augment, currentParent); + targetModule = findModuleFromBuilders(modules, module, qname.getPrefix(), line); + } + + if (targetModule == null && context != null) { + Module m = findModuleFromContext(context, module, prefix, line); + targetModule = new ModuleBuilder(m); + DataSchemaNode firstNode = m.getDataChildByName(qname.getLocalName()); + DataSchemaNodeBuilder firstNodeWrapped = wrapChildNode(targetModule.getModuleName(), line, firstNode, + targetModule.getPath(), firstNode.getQName()); + targetModule.addChildNode(firstNodeWrapped); + + TreeMap map = new TreeMap<>(); + map.put(targetModule.getRevision(), targetModule); + modules.put(targetModule.getModuleName(), map); } + + return targetModule; } /** @@ -795,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(); @@ -824,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(); @@ -877,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()) { @@ -895,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()) { @@ -908,68 +1204,125 @@ 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()) { - final int line = usesNode.getLine(); DataNodeContainerBuilder parent = usesNode.getParent(); ModuleBuilder module = ParserUtils.getParentModule(parent); GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); if (target == null) { - URI ns = null; - Date rev = null; - String prefix = null; - if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) { - ns = module.getNamespace(); - rev = module.getRevision(); - prefix = module.getPrefix(); - } else { - ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace(); - rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision(); - prefix = ((DataSchemaNodeBuilder) parent).getQName().getPrefix(); - } - - Set childNodes = GroupingUtils.getTargetGroupingDefinitionNodesWithNewNamespace( - usesNode, ns, rev, prefix, module.getName(), line); - parent.getChildNodeBuilders().addAll(childNodes); - Set typedefs = GroupingUtils - .getTargetGroupingDefinitionTypedefsWithNewNamespace(usesNode, ns, rev, prefix, - module.getName(), line); - parent.getTypeDefinitionBuilders().addAll(typedefs); - Set groupings = GroupingUtils.getTargetGroupingDefinitionGroupingsWithNewNamespace( - usesNode, ns, rev, prefix, module.getName(), line); - parent.getGroupingBuilders().addAll(groupings); - List unknownNodes = GroupingUtils - .getTargetGroupingDefinitionUnknownNodesWithNewNamespace(usesNode, ns, rev, prefix, - module.getName(), line); - parent.getUnknownNodeBuilders().addAll(unknownNodes); + resolveUsesWithContext(usesNode); usesNode.setResolved(true); - for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { - processAugmentationOnContext(augment, augment.getTargetPath().getPath(), module, prefix, context); + resolveUsesAugment(augment, module, modules, context); } } else { parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent)); parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent)); parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent)); - parent.getUnknownNodeBuilders().addAll(target.instantiateUnknownNodes(parent)); + parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); usesNode.setResolved(true); - for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { - processAugmentation(augment, parent); + resolveUsesAugment(augment, module, modules, context); } } GroupingUtils.performRefine(usesNode); } } + /** + * 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(); + ModuleBuilder module = ParserUtils.getParentModule(parent); + SchemaPath parentPath; + URI ns = null; + Date rev = null; + String pref = null; + if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) { + ns = module.getNamespace(); + rev = module.getRevision(); + pref = module.getPrefix(); + if (parent instanceof AugmentationSchemaBuilder) { + parentPath = ((AugmentationSchemaBuilder)parent).getTargetNodeSchemaPath(); + } else { + parentPath = ((ModuleBuilder)parent).getPath(); + } + } else { + ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace(); + rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision(); + pref = ((DataSchemaNodeBuilder) parent).getQName().getPrefix(); + parentPath = ((DataSchemaNodeBuilder)parent).getPath(); + } + + GroupingDefinition gd = usesNode.getGroupingDefinition(); + + Set childNodes = wrapChildNodes(module.getModuleName(), line, + gd.getChildNodes(), parentPath, ns, rev, pref); + parent.getChildNodeBuilders().addAll(childNodes); + for (DataSchemaNodeBuilder childNode : childNodes) { + setNodeAddedByUses(childNode); + } + + Set typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, ns, + rev, pref); + parent.getTypeDefinitionBuilders().addAll(typedefs); + for (TypeDefinitionBuilder typedef : typedefs) { + setNodeAddedByUses(typedef); + } + + Set groupings = wrapGroupings(module.getModuleName(), line, usesNode + .getGroupingDefinition().getGroupings(), parentPath, ns, rev, pref); + parent.getGroupingBuilders().addAll(groupings); + for (GroupingBuilder gb : groupings) { + setNodeAddedByUses(gb); + } + + List unknownNodes = wrapUnknownNodes(module.getModuleName(), line, + gd.getUnknownSchemaNodes(), parentPath, ns, rev, pref); + parent.getUnknownNodes().addAll(unknownNodes); + for (UnknownSchemaNodeBuilder un : unknownNodes) { + un.setAddedByUses(true); + } + } + + /** + * 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); @@ -983,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()) { @@ -1003,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; @@ -1043,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(); @@ -1090,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();