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=d0335a4667889c4e9d40ca86a703700ac01a2b35;hb=752f127fb427346655185457d6c38f289595ab2d;hp=e705f9c1d5b6f48b8700f30905eb022309238158;hpb=0154c433eb95540a81ef9630a05767791015a835;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 e705f9c1d5..d0335a4667 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 @@ -1,6 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html @@ -8,25 +7,18 @@ package org.opendaylight.yangtools.yang.parser.impl; 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.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; - +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.fillAugmentTarget; +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity; +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findModuleFromContext; +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNode; +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNodeInModule; +import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.processAugmentation; +import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveType; +import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveTypeUnion; + +import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; import com.google.common.collect.HashBiMap; import com.google.common.io.ByteSource; import java.io.File; @@ -45,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import javax.annotation.concurrent.Immutable; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.ParseTree; @@ -53,67 +46,66 @@ 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.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; -import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; 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.YangContextParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; 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; +import org.opendaylight.yangtools.yang.parser.builder.api.ExtensionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder; 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.UnknownSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; 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.GroupingUtils; 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.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.builder.util.Comparators; import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort; import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream; import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream; 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; - +@Immutable public final class YangParserImpl implements YangContextParser { private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class); + private static final Splitter COLON_SPLITTER = Splitter.on(':'); + private static final YangParserImpl INSTANCE = new YangParserImpl(); - private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target."; + public static YangParserImpl getInstance() { + return INSTANCE; + } @Override + @Deprecated public Set parseYangModels(final File yangFile, final File directory) { try { return parseFile(yangFile, directory).getModules(); - } catch (IOException e) { + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } } @Override - public SchemaContext parseFile(final File yangFile, final File directory) throws IOException { + public SchemaContext parseFile(final File yangFile, final File directory) throws IOException, YangSyntaxErrorException { Preconditions.checkState(yangFile.exists(), yangFile + " does not exists"); Preconditions.checkState(directory.exists(), directory + " does not exists"); Preconditions.checkState(directory.isDirectory(), directory + " is not a directory"); @@ -122,7 +114,7 @@ public final class YangParserImpl implements YangContextParser { final String[] fileList = checkNotNull(directory.list(), directory + " not found or is not a directory"); Map sourceToFile = new LinkedHashMap<>(); - ByteSource mainFileSource = ParserUtils.fileToByteSource(yangFile); + ByteSource mainFileSource = BuilderUtils.fileToByteSource(yangFile); sourceToFile.put(mainFileSource, yangFile); for (String fileName : fileList) { @@ -131,11 +123,11 @@ public final class YangParserImpl implements YangContextParser { } File dependency = new File(directory, fileName); if (dependency.isFile()) { - sourceToFile.put(ParserUtils.fileToByteSource(dependency), dependency); + sourceToFile.put(BuilderUtils.fileToByteSource(dependency), dependency); } } - Map sourceToBuilder = parseSourcesToBuilders(sourceToFile.keySet()); + Map sourceToBuilder = parseSourcesToBuilders(sourceToFile.keySet(), null); ModuleBuilder main = sourceToBuilder.get(mainFileSource); List moduleBuilders = new ArrayList<>(); @@ -145,7 +137,7 @@ public final class YangParserImpl implements YangContextParser { // module builders sorted by dependencies List sortedBuilders = ModuleDependencySort.sort(resolved); - LinkedHashMap> modules = orderModules(sortedBuilders); + LinkedHashMap> modules = resolveModulesWithImports(sortedBuilders, null); Collection unsorted = build(modules).values(); Set result = new LinkedHashSet<>( ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); @@ -153,6 +145,7 @@ public final class YangParserImpl implements YangContextParser { } @Override + @Deprecated public Set parseYangModels(final List yangFiles) { return parseFiles(yangFiles).getModules(); } @@ -166,61 +159,64 @@ public final class YangParserImpl implements YangContextParser { } @Override + @Deprecated public Set parseYangModels(final List yangFiles, final SchemaContext context) { try { return parseFiles(yangFiles, context).getModules(); - } catch (IOException e) { + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } } @Override - public SchemaContext parseFiles(final Collection yangFiles, final SchemaContext context) throws IOException { + public SchemaContext parseFiles(final Collection yangFiles, final SchemaContext context) throws IOException, + YangSyntaxErrorException { if (yangFiles == null) { return resolveSchemaContext(Collections. emptySet()); } - Collection sources = ParserUtils.filesToByteSources(yangFiles); - SchemaContext result = parseSources(sources, context); - return result; + Collection sources = BuilderUtils.filesToByteSources(yangFiles); + return parseSources(sources, context); } @Override + @Deprecated public Set parseYangModelsFromStreams(final List yangModelStreams) { - Collection sources = ParserUtils.streamsToByteSources(yangModelStreams); try { + Collection sources = BuilderUtils.streamsToByteSources(yangModelStreams); return parseSources(sources).getModules(); - } catch (IOException e) { + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } } @Override - public SchemaContext parseSources(Collection sources) throws IOException { - Collection unsorted = parseYangModelSources(sources).values(); - Set sorted = new LinkedHashSet<>( - ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); - return resolveSchemaContext(sorted); + public SchemaContext parseSources(final Collection sources) throws IOException,YangSyntaxErrorException { + return assembleContext(parseYangModelSources(sources, null).values()); } @Override - public Set parseYangModelsFromStreams(final List yangModelStreams, SchemaContext context) { - Collection sources = ParserUtils.streamsToByteSources(yangModelStreams); + @Deprecated + public Set parseYangModelsFromStreams(final List yangModelStreams, final SchemaContext context) { try { + Collection sources = BuilderUtils.streamsToByteSources(yangModelStreams); return parseSources(sources, context).getModules(); - } catch (IOException e) { + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } } @Override - public SchemaContext parseSources(Collection sources, SchemaContext context) throws IOException { + public SchemaContext parseSources(final Collection sources, final SchemaContext context) + throws IOException, YangSyntaxErrorException { if (sources == null) { return resolveSchemaContext(Collections. emptySet()); } - final Map> modules = resolveModuleBuilders(sources, context); - final Set unsorted = new LinkedHashSet<>(buildWithContext(modules, context).values()); + final List sorted = resolveModuleBuilders(sources, context); + final Map> modules = resolveModulesWithImports(sorted, context); + + final Set unsorted = new LinkedHashSet<>(build(modules).values()); if (context != null) { for (Module m : context.getModules()) { if (!unsorted.contains(m)) { @@ -233,8 +229,35 @@ public final class YangParserImpl implements YangContextParser { return resolveSchemaContext(result); } + private static LinkedHashMap> resolveModulesWithImports(final List sorted, + final SchemaContext context) { + final LinkedHashMap> modules = orderModules(sorted); + for (ModuleBuilder module : sorted) { + if (module != null) { + for (ModuleImport imp : module.getImports().values()) { + String prefix = imp.getPrefix(); + ModuleBuilder targetModule = BuilderUtils.findModuleFromBuilders(imp, sorted); + if (targetModule == null) { + Module result = findModuleFromContext(context, module, prefix, 0); + targetModule = new ModuleBuilder(result); + TreeMap map = modules.get(prefix); + if (map == null) { + map = new TreeMap<>(); + map.put(targetModule.getRevision(), targetModule); + modules.put(targetModule.getNamespace(), map); + } else { + map.put(targetModule.getRevision(), targetModule); + } + } + module.addImportedModule(prefix, targetModule); + } + } + } + return modules; + } + @Override - public Map parseYangModelsMapped(Collection yangFiles) { + public Map parseYangModelsMapped(final Collection yangFiles) { if (yangFiles == null || yangFiles.isEmpty()) { return Collections.emptyMap(); } @@ -252,8 +275,8 @@ public final class YangParserImpl implements YangContextParser { Map byteSourceToModule; try { - byteSourceToModule = parseYangModelSources(byteSourceToFile.keySet()); - } catch (IOException e) { + byteSourceToModule = parseYangModelSources(byteSourceToFile.keySet(), null); + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } Map result = new LinkedHashMap<>(); @@ -282,8 +305,8 @@ public final class YangParserImpl implements YangContextParser { Map sourceToModule; try { - sourceToModule = parseYangModelSources(sourceToStream.keySet()); - } catch (IOException e) { + sourceToModule = parseYangModelSources(sourceToStream.keySet(), null); + } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } Map result = new LinkedHashMap<>(); @@ -295,25 +318,39 @@ public final class YangParserImpl implements YangContextParser { @Override public SchemaContext resolveSchemaContext(final Set modules) { - // after merging parse method with this one, add support for getting submodule sources. + // after merging parse method with this one, add support for getting + // submodule sources. Map identifiersToSources = new HashMap<>(); - for(Module module: modules) { + for (Module module : modules) { ModuleImpl moduleImpl = (ModuleImpl) module; identifiersToSources.put(module, moduleImpl.getSource()); } return new SchemaContextImpl(modules, identifiersToSources); } - private Map parseYangModelSources(final Collection sources) throws IOException { + public Collection buildModules(final Collection builders) { + List sorted = ModuleDependencySort.sort(builders); + Map> modules = resolveModulesWithImports(sorted, null); + Map builderToModule = build(modules); + + return builderToModule.values(); + } + + public SchemaContext assembleContext(final Collection modules) { + final Set sorted = new LinkedHashSet<>( + ModuleDependencySort.sort(modules.toArray(new Module[modules.size()]))); + return resolveSchemaContext(sorted); + } + + private Map parseYangModelSources(final Collection sources, final SchemaContext context) throws IOException, YangSyntaxErrorException { if (sources == null || sources.isEmpty()) { return Collections.emptyMap(); } - Map sourceToBuilder = resolveSources(sources); + Map sourceToBuilder = resolveSources(sources, context); // sort and check for duplicates List sorted = ModuleDependencySort.sort(sourceToBuilder.values()); - ParserUtils.setSourceToBuilder(sourceToBuilder); - Map> modules = orderModules(sorted); + Map> modules = resolveModulesWithImports(sorted, null); Map builderToModule = build(modules); Map builderToSource = HashBiMap.create(sourceToBuilder).inverse(); sorted = ModuleDependencySort.sort(builderToModule.keySet()); @@ -334,14 +371,16 @@ public final class YangParserImpl implements YangContextParser { * collection of streams to parse * @return map, where key is source stream and value is module builder * parsed from stream + * @throws YangSyntaxErrorException */ - private Map resolveSources(Collection streams) throws IOException { - Map builders = parseSourcesToBuilders(streams); - Map result = resolveSubmodules(builders); - return result; + // TODO: remove ByteSource result after removing YangModelParser + private Map resolveSources(final Collection streams, final SchemaContext context) throws IOException, YangSyntaxErrorException { + Map builders = parseSourcesToBuilders(streams, context); + return resolveSubmodules(builders); } - private Map parseSourcesToBuilders(Collection sources) throws IOException { + private Map parseSourcesToBuilders(final Collection sources, + final SchemaContext context) throws IOException, YangSyntaxErrorException { final ParseTreeWalker walker = new ParseTreeWalker(); final Map sourceToTree = parseYangSources(sources); final Map sourceToBuilder = new LinkedHashMap<>(); @@ -349,49 +388,78 @@ public final class YangParserImpl implements YangContextParser { // validate yang new YangModelBasicValidator(walker).validate(sourceToTree.values()); + Map> namespaceContext = BuilderUtils.createYangNamespaceContext( + sourceToTree.values(), Optional.fromNullable(context)); YangParserListenerImpl yangModelParser; for (Map.Entry entry : sourceToTree.entrySet()) { ByteSource source = entry.getKey(); - String path = null; - InputStream stream = source.openStream(); - if (stream instanceof NamedInputStream) { - path = stream.toString(); - } - try { - stream.close(); - } catch (IOException e) { - LOG.warn("Failed to close stream {}", stream); + String path = null; // TODO refactor to Optional + // TODO refactor so that path can be retrieved without opening + // stream: NamedInputStream -> NamedByteSource ? + try (InputStream stream = source.openStream()) { + if (stream instanceof NamedInputStream) { + path = stream.toString(); + } } - - yangModelParser = new YangParserListenerImpl(path); + yangModelParser = new YangParserListenerImpl(namespaceContext, path); walker.walk(yangModelParser, entry.getValue()); ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder(); + moduleBuilder.setSource(source); sourceToBuilder.put(source, moduleBuilder); } - return sourceToBuilder; } - private Map resolveSubmodules(Map builders) { + private Map resolveSubmodules(final Map builders) { Map modules = new HashMap<>(); - Set submodules = new HashSet<>(); + Map> submodules = new HashMap<>(); for (Map.Entry entry : builders.entrySet()) { - ModuleBuilder moduleBuilder = entry.getValue(); - if (moduleBuilder.isSubmodule()) { - submodules.add(moduleBuilder); + ModuleBuilder builder = entry.getValue(); + if (builder.isSubmodule()) { + String submoduleName = builder.getName(); + TreeMap map = submodules.get(submoduleName); + if (map == null) { + map = new TreeMap<>(); + map.put(builder.getRevision(), builder); + submodules.put(submoduleName, map); + } else { + map.put(builder.getRevision(), builder); + } } else { - modules.put(entry.getKey(), moduleBuilder); + modules.put(entry.getKey(), builder); } } - Collection values = modules.values(); - for (ModuleBuilder submodule : submodules) { - for (ModuleBuilder module : values) { - if (module.getName().equals(submodule.getBelongsTo())) { - addSubmoduleToModule(submodule, module); + for (ModuleBuilder module : modules.values()) { + resolveSubmodules(module, submodules); + } + + return modules; + } + + private Collection resolveSubmodules(final Collection builders) { + Collection modules = new HashSet<>(); + Map> submodules = new HashMap<>(); + for (ModuleBuilder builder : builders) { + if (builder.isSubmodule()) { + String submoduleName = builder.getName(); + TreeMap map = submodules.get(submoduleName); + if (map == null) { + map = new TreeMap<>(); + map.put(builder.getRevision(), builder); + submodules.put(submoduleName, map); + } else { + map.put(builder.getRevision(), builder); } + } else { + modules.add(builder); } } + + for (ModuleBuilder module : modules) { + resolveSubmodules(module, submodules); + } + return modules; } @@ -399,40 +467,50 @@ public final class YangParserImpl implements YangContextParser { * Traverse collection of builders, find builders representing submodule and * add this submodule to its parent module. * - * @param builders - * collection of builders containing modules and submodules - * @return collection of module builders + * @param module + * current module + * @param submodules + * collection all loaded submodules + * @return collection of module builders with resolved submodules */ - private Collection resolveSubmodules(Collection builders) { - Collection modules = new HashSet<>(); - Set submodules = new HashSet<>(); - for (ModuleBuilder moduleBuilder : builders) { - if (moduleBuilder.isSubmodule()) { - submodules.add(moduleBuilder); + private void resolveSubmodules(final ModuleBuilder module, + final Map> submodules) { + Map includes = module.getIncludedModules(); + for (Map.Entry entry : includes.entrySet()) { + TreeMap subs = submodules.get(entry.getKey()); + if (subs == null) { + throw new YangParseException("Failed to find references submodule " + entry.getKey() + " in module " + + module.getName()); + } + Date rev = entry.getValue(); + ModuleBuilder submodule; + if (rev == null) { + submodule = subs.lastEntry().getValue(); } else { - modules.add(moduleBuilder); + submodule = subs.get(rev); + // FIXME an exception should be thrown after issue with + // submodule's revisions and namespaces will be resolved + if (submodule == null) { + submodule = subs.lastEntry().getValue(); + } } - } - for (ModuleBuilder submodule : submodules) { - for (ModuleBuilder module : modules) { - if (module.getName().equals(submodule.getBelongsTo())) { - addSubmoduleToModule(submodule, module); - } + if (submodule.getIncludedModules().size() > 0) { + resolveSubmodules(submodule, submodules); } + addSubmoduleToModule(submodule, module); } - return modules; } - private void addSubmoduleToModule(ModuleBuilder submodule, ModuleBuilder module) { + private void addSubmoduleToModule(final ModuleBuilder submodule, final ModuleBuilder module) { submodule.setParent(module); module.getDirtyNodes().addAll(submodule.getDirtyNodes()); - module.getModuleImports().addAll(submodule.getModuleImports()); + module.getImports().putAll(submodule.getImports()); 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.getChildNodes().putAll(submodule.getChildNodes()); module.getGroupings().addAll(submodule.getGroupings()); module.getGroupingBuilders().addAll(submodule.getGroupingBuilders()); module.getTypeDefinitions().addAll(submodule.getTypeDefinitions()); @@ -457,9 +535,9 @@ public final class YangParserImpl implements YangContextParser { module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes()); } - private Map> resolveModuleBuilders( - final Collection yangFileStreams, final SchemaContext context) throws IOException { - Map parsedBuilders = resolveSources(yangFileStreams); + private List resolveModuleBuilders(final Collection yangFileStreams, + final SchemaContext context) throws IOException, YangSyntaxErrorException { + Map parsedBuilders = resolveSources(yangFileStreams, context); ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()]; parsedBuilders.values().toArray(builders); @@ -470,33 +548,38 @@ public final class YangParserImpl implements YangContextParser { } else { sorted = ModuleDependencySort.sortWithContext(context, builders); } - return orderModules(sorted); + return sorted; } /** - * Order modules by name and revision. + * Order modules by namespace and revision. * * @param modules - * modules to order - * @return modules ordered by name and revision + * topologically sorted modules + * @return modules ordered by namespace and revision */ - private LinkedHashMap> orderModules(List modules) { - final LinkedHashMap> result = new LinkedHashMap<>(); + private static LinkedHashMap> orderModules(final List modules) { + final LinkedHashMap> result = new LinkedHashMap<>(); for (final ModuleBuilder builder : modules) { if (builder == null) { continue; } - final String builderName = builder.getName(); - Date builderRevision = builder.getRevision(); - if (builderRevision == null) { - builderRevision = new Date(0L); + + URI ns = builder.getNamespace(); + Date rev = builder.getRevision(); + if (rev == null) { + rev = new Date(0); } - TreeMap builderByRevision = result.get(builderName); + + TreeMap builderByRevision = result.get(ns); if (builderByRevision == null) { builderByRevision = new TreeMap<>(); + builderByRevision.put(rev, builder); + result.put(ns, builderByRevision); + } else { + builderByRevision.put(rev, builder); } - builderByRevision.put(builderRevision, builder); - result.put(builderName, builderByRevision); + } return result; } @@ -512,8 +595,9 @@ public final class YangParserImpl implements YangContextParser { * @param filtered * collection to fill up */ - private void filterImports(ModuleBuilder main, Collection other, Collection filtered) { - Set imports = main.getModuleImports(); + private void filterImports(final ModuleBuilder main, final Collection other, + final Collection filtered) { + Map imports = main.getImports(); // if this is submodule, add parent to filtered and pick its imports if (main.isSubmodule()) { @@ -525,10 +609,10 @@ public final class YangParserImpl implements YangContextParser { } ModuleBuilder parent = dependencies.get(dependencies.firstKey()); filtered.add(parent); - imports.addAll(parent.getModuleImports()); + imports.putAll(parent.getImports()); } - for (ModuleImport mi : imports) { + for (ModuleImport mi : imports.values()) { for (ModuleBuilder builder : other) { if (mi.getModuleName().equals(builder.getModuleName())) { if (mi.getRevision() == null) { @@ -549,40 +633,37 @@ public final class YangParserImpl implements YangContextParser { } } - private Map parseYangSources(final Collection sources) throws IOException { + private Map parseYangSources(final Collection sources) throws IOException, YangSyntaxErrorException { final Map trees = new HashMap<>(); for (ByteSource source : sources) { - trees.put(source, parseYangSource(source)); + try (InputStream stream = source.openStream()) { + trees.put(source, parseYangSource(stream)); + } } return trees; } - private ParseTree parseYangSource(final ByteSource source) throws IOException { - ParseTree result = null; - InputStream stream = null; - try { - stream = source.openStream(); - final ANTLRInputStream input = new ANTLRInputStream(stream); - final YangLexer lexer = new YangLexer(input); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final YangParser parser = new YangParser(tokens); - parser.removeErrorListeners(); - YangErrorListener errorListener = new YangErrorListener(); - parser.addErrorListener(errorListener); - result = parser.yang(); - errorListener.validate(); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - LOG.warn("Failed to close stream {}", stream); - } - } - } + public static YangContext parseYangSource(final InputStream stream) throws IOException, YangSyntaxErrorException { + final YangLexer lexer = new YangLexer(new ANTLRInputStream(stream)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + final YangParser parser = new YangParser(tokens); + parser.removeErrorListeners(); + + final YangErrorListener errorListener = new YangErrorListener(); + parser.addErrorListener(errorListener); + + final YangContext result = parser.yang(); + errorListener.validate(); + return result; } + /** + * Mini parser: This parsing context does not validate full YANG module, + * only parses header up to the revisions and imports. + * + * @see org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo + */ public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) { YangContext result = null; try { @@ -619,65 +700,18 @@ public final class YangParserImpl implements YangContextParser { * all loaded modules * @return modules mapped on their builders */ - private Map build(final Map> modules) { + private Map build(final Map> modules) { resolveDirtyNodes(modules); - resolveAugmentsTargetPath(modules, null); - resolveUsesTargetGrouping(modules, null); - resolveUsesForGroupings(modules, null); - resolveUsesForNodes(modules, null); - resolveAugments(modules, null); + resolveAugmentsTargetPath(modules); + resolveUsesTargetGrouping(modules); + resolveUsesForGroupings(modules); + resolveUsesForNodes(modules); + resolveAugments(modules); resolveIdentities(modules); - resolveDeviations(modules); // build final Map result = new LinkedHashMap<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry childEntry : entry.getValue().entrySet()) { - final ModuleBuilder moduleBuilder = childEntry.getValue(); - final Module module = moduleBuilder.build(); - result.put(moduleBuilder, module); - } - } - 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) { - resolvedDirtyNodesWithContext(modules, context); - resolveAugmentsTargetPath(modules, context); - resolveUsesTargetGrouping(modules, context); - resolveUsesForGroupings(modules, context); - resolveUsesForNodes(modules, context); - resolveAugments(modules, context); - resolveIdentitiesWithContext(modules, context); - resolveDeviationsWithContext(modules, context); - - // build - final Map result = new LinkedHashMap<>(); - for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry childEntry : entry.getValue().entrySet()) { final ModuleBuilder moduleBuilder = childEntry.getValue(); final Module module = moduleBuilder.build(); @@ -693,8 +727,8 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveDirtyNodes(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { + private void resolveDirtyNodes(final Map> modules) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry childEntry : entry.getValue().entrySet()) { final ModuleBuilder module = childEntry.getValue(); resolveUnknownNodes(modules, module); @@ -703,25 +737,6 @@ public final class YangParserImpl implements YangContextParser { } } - /** - * 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()) { - for (Map.Entry childEntry : entry.getValue().entrySet()) { - final ModuleBuilder module = childEntry.getValue(); - resolveUnknownNodesWithContext(modules, module, context); - resolveDirtyNodesWithContext(modules, module, context); - } - } - } - /** * Search for dirty nodes (node which contains UnknownType) and resolve * unknown types. @@ -731,7 +746,7 @@ public final class YangParserImpl implements YangContextParser { * @param module * current module */ - private void resolveDirtyNodes(final Map> modules, final ModuleBuilder module) { + private void resolveDirtyNodes(final Map> modules, final ModuleBuilder module) { final Set dirtyNodes = module.getDirtyNodes(); if (!dirtyNodes.isEmpty()) { for (TypeAwareBuilder nodeToResolve : dirtyNodes) { @@ -741,7 +756,7 @@ public final class YangParserImpl implements YangContextParser { } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { // special handling for identityref types IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef(); - IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(), + IdentitySchemaNodeBuilder identity = findBaseIdentity(module, idref.getBaseString(), idref.getLine()); if (identity == null) { throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity"); @@ -755,121 +770,65 @@ public final class YangParserImpl implements YangContextParser { } } - private void resolveDirtyNodesWithContext(final Map> modules, - final ModuleBuilder module, SchemaContext context) { - final Set dirtyNodes = module.getDirtyNodes(); - if (!dirtyNodes.isEmpty()) { - for (TypeAwareBuilder nodeToResolve : dirtyNodes) { - if (nodeToResolve instanceof UnionTypeBuilder) { - // special handling for union types - resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context); - } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { - // special handling for identityref types - IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef(); - IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(), - idref.getLine()); - idref.setBaseIdentity(identity); - nodeToResolve.setType(idref.build()); - } else { - resolveTypeWithContext(nodeToResolve, modules, module, context); - } - } - } - } - /** * 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) { + private void resolveAugmentsTargetPath(final Map> modules) { // collect augments from all loaded modules final List allAugments = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { allAugments.addAll(inner.getValue().getAllAugments()); } } for (AugmentationSchemaBuilder augment : allAugments) { - setCorrectAugmentTargetPath(modules, augment, context); + setCorrectAugmentTargetPath(augment); } } /** * 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); - SchemaPath oldSchemaPath = augment.getTargetPath(); - List oldPath = oldSchemaPath.getPath(); - List newPath = new ArrayList<>(); - + private void setCorrectAugmentTargetPath(final AugmentationSchemaBuilder augment) { Builder parent = augment.getParent(); - if (parent instanceof UsesNodeBuilder) { - DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent(); - newPath.addAll(usesParent.getPath().getPath()); - - URI ns; - Date revision; - String prefix; - QName baseQName = usesParent.getQName(); - if (baseQName == null) { - ModuleBuilder m = ParserUtils.getParentModule(usesParent); - ns = m.getNamespace(); - revision = m.getRevision(); - prefix = m.getPrefix(); - } else { - ns = baseQName.getNamespace(); - revision = baseQName.getRevision(); - prefix = baseQName.getPrefix(); - } + final SchemaPath targetNodeSchemaPath; - for (QName qn : oldSchemaPath.getPath()) { - newPath.add(new QName(ns, revision, prefix, qn.getLocalName())); - } + if (parent instanceof UsesNodeBuilder) { + targetNodeSchemaPath = findUsesAugmentTargetNodePath(((UsesNodeBuilder) parent).getParent(), augment); } else { - for (QName qn : oldPath) { - URI ns = module.getNamespace(); - Date rev = module.getRevision(); - String localPrefix = qn.getPrefix(); - if (localPrefix != null && !("".equals(localPrefix))) { - ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix, - augment.getLine()); - if (currentModule == null) { - Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine()); - if (m == null) { - throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix " - + localPrefix + " not found."); - } - ns = m.getNamespace(); - rev = m.getRevision(); - } else { - ns = currentModule.getNamespace(); - rev = currentModule.getRevision(); - } - } - newPath.add(new QName(ns, rev, localPrefix, qn.getLocalName())); - } + targetNodeSchemaPath = augment.getTargetPath(); } - augment.setTargetNodeSchemaPath(new SchemaPath(newPath, true)); for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { - correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath()); + correctPathForAugmentNodes(childNode, targetNodeSchemaPath); + } + } + + private SchemaPath findUsesAugmentTargetNodePath(DataNodeContainerBuilder usesParent, + AugmentationSchemaBuilder augment) { + QName parentQName = usesParent.getQName(); + final QNameModule qnm; + if (parentQName == null) { + ModuleBuilder m = BuilderUtils.getParentModule(usesParent); + qnm = m.getQNameModule(); + } else { + qnm = parentQName.getModule(); + } + + SchemaPath path = usesParent.getPath(); + for (QName qname : augment.getTargetPath().getPathFromRoot()) { + path = path.createChild(QName.create(qnm, qname.getLocalName())); } + + return path; } /** @@ -881,8 +840,8 @@ public final class YangParserImpl implements YangContextParser { * @param parentPath * schema path of parent node */ - private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) { - SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName()); + private void correctPathForAugmentNodes(final DataSchemaNodeBuilder node, final SchemaPath parentPath) { + SchemaPath newPath = parentPath.createChild(node.getQName()); node.setPath(newPath); if (node instanceof DataNodeContainerBuilder) { for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) { @@ -890,7 +849,7 @@ public final class YangParserImpl implements YangContextParser { } } if (node instanceof ChoiceBuilder) { - for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) { + for (ChoiceCaseBuilder child : ((ChoiceBuilder) node).getCases()) { correctPathForAugmentNodes(child, node.getPath()); } } @@ -904,13 +863,13 @@ public final class YangParserImpl implements YangContextParser { * @param augments * augments to check */ - private void checkAugmentMandatoryNodes(Collection augments) { + private void checkAugmentMandatoryNodes(final Collection augments) { for (AugmentationSchemaBuilder augment : augments) { - String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix(); - ModuleBuilder module = ParserUtils.getParentModule(augment); - String modulePrefix = module.getPrefix(); + URI augmentTargetNs = augment.getTargetPath().getPathFromRoot().iterator().next().getNamespace(); + Date augmentTargetRev = augment.getTargetPath().getPathFromRoot().iterator().next().getRevision(); + ModuleBuilder module = BuilderUtils.getParentModule(augment); - if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) { + if (augmentTargetNs.equals(module.getNamespace()) && augmentTargetRev.equals(module.getRevision())) { continue; } @@ -928,33 +887,25 @@ public final class YangParserImpl implements YangContextParser { * Go through all augment definitions and resolve them. * * @param modules - * all loaded modules - * @param context - * SchemaContext containing already resolved modules + * all loaded modules topologically sorted (based on dependencies + * between each other) */ - private void resolveAugments(final Map> modules, final SchemaContext context) { + private void resolveAugments(final Map> modules) { List all = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { all.add(inner.getValue()); } } - List sorted; - if (context == null) { - sorted = ModuleDependencySort.sort(all.toArray(new ModuleBuilder[all.size()])); - } else { - sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()])); - } - - for (ModuleBuilder mb : sorted) { + for (ModuleBuilder mb : all) { if (mb != null) { List augments = mb.getAllAugments(); checkAugmentMandatoryNodes(augments); - Collections.sort(augments, Comparators.AUGMENT_COMP); + Collections.sort(augments, Comparators.AUGMENT_BUILDER_COMP); for (AugmentationSchemaBuilder augment : augments) { if (!(augment.isResolved())) { - boolean resolved = resolveAugment(augment, mb, modules, context); + boolean resolved = resolveAugment(augment, mb, modules); if (!resolved) { throw new YangParseException(augment.getModuleName(), augment.getLine(), "Error in augment parsing: failed to find augment target: " + augment); @@ -974,34 +925,54 @@ public final class YangParserImpl implements YangContextParser { * 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) { + final Map> modules) { if (augment.isResolved()) { return true; } UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent(); DataNodeContainerBuilder parentNode = usesNode.getParent(); - SchemaNodeBuilder targetNode; - if (parentNode instanceof ModuleBuilder) { - targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder) parentNode); + Optional potentialTargetNode; + SchemaPath resolvedTargetPath = findUsesAugmentTargetNodePath(parentNode, augment); + if (parentNode instanceof ModuleBuilder && resolvedTargetPath.isAbsolute()) { + // Uses is directly used in module body, we lookup + // We lookup in data namespace to find correct augmentation target + potentialTargetNode = findSchemaNodeInModule(resolvedTargetPath, (ModuleBuilder) parentNode); } else { - targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder) parentNode); - } - - if (targetNode instanceof AugmentationTargetBuilder) { - fillAugmentTarget(augment, targetNode); - ((AugmentationTargetBuilder) targetNode).addAugmentation(augment); - augment.setResolved(true); - return true; + // Uses is used in local context (be it data namespace or grouping + // namespace, + // since all nodes via uses are imported to localName, it is safe to + // to proceed only with local names. + // + // Conflicting elements in other namespaces are still not present + // since resolveUsesAugment occurs before augmenting from external + // modules. + potentialTargetNode = Optional. fromNullable(findSchemaNode(augment.getTargetPath() + .getPathFromRoot(), (SchemaNodeBuilder) parentNode)); + } + + if (potentialTargetNode.isPresent()) { + SchemaNodeBuilder targetNode = potentialTargetNode.get(); + if (targetNode instanceof AugmentationTargetBuilder) { + fillAugmentTarget(augment, targetNode); + ((AugmentationTargetBuilder) targetNode).addAugmentation(augment); + augment.setResolved(true); + return true; + } else { + LOG.warn( + "Error in module {} at line {}: Unsupported augment target: {}. Augmentation process skipped.", + module.getName(), augment.getLine(), potentialTargetNode); + augment.setResolved(true); + return true; + } } else { - throw new YangParseException(module.getName(), augment.getLine(), - "Failed to resolve augment in uses. Invalid augment target: " + targetNode); + throw new YangParseException(module.getName(), augment.getLine(), String.format( + "Failed to resolve augment in uses. Invalid augment target path: %s", augment.getTargetPath())); } + } /** @@ -1013,18 +984,16 @@ public final class YangParserImpl implements YangContextParser { * 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) { + final Map> modules) { if (augment.isResolved()) { return true; } - List targetPath = augment.getTargetPath().getPath(); - ModuleBuilder targetModule = findTargetModule(targetPath.get(0), module, modules, context, augment.getLine()); + QName targetModuleName = augment.getTargetPath().getPathFromRoot().iterator().next(); + ModuleBuilder targetModule = BuilderUtils.findModule(targetModuleName, modules); if (targetModule == null) { throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment " + augment); @@ -1033,146 +1002,44 @@ public final class YangParserImpl implements YangContextParser { 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 { - 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; - } - - private ModuleBuilder findTargetModule(final String prefix, final ModuleBuilder module, - final Map> modules, final SchemaContext context, final int line) { - ModuleBuilder targetModule = null; - - if (prefix == null || prefix.equals("")) { - targetModule = module; - } else { - targetModule = findModuleFromBuilders(modules, module, prefix, line); - } - - if (targetModule == null && context != null) { - Module m = findModuleFromContext(context, module, prefix, line); - if (m != null) { - targetModule = new ModuleBuilder(m); - TreeMap map = new TreeMap<>(); - map.put(targetModule.getRevision(), targetModule); - modules.put(targetModule.getModuleName(), map); - } - } - - return targetModule; - } - /** * Go through identity statements defined in current module and resolve - * their 'base' statement if present. + * their 'base' statement. * * @param modules - * all modules - * @param module - * module being resolved + * all loaded modules */ - private void resolveIdentities(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { + private void resolveIdentities(final Map> modules) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { ModuleBuilder module = inner.getValue(); final Set identities = module.getAddedIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { - final String baseIdentityName = identity.getBaseIdentityName(); - final int line = identity.getLine(); - if (baseIdentityName != null) { - IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line); - if (baseIdentity == null) { - throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity"); - } else { - identity.setBaseIdentity(baseIdentity); - } - } + resolveIdentity(module, identity); } - } } } - /** - * Go through identity statements defined in current module and resolve - * their 'base' statement. Method tries to find base identity in given - * modules. If base identity is not found, method will search it in context. - * - * @param modules - * all loaded modules - * @param module - * current module - * @param context - * SchemaContext containing already resolved modules - */ - private void resolveIdentitiesWithContext(final Map> modules, - final SchemaContext context) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder module = inner.getValue(); - final Set identities = module.getAddedIdentities(); - for (IdentitySchemaNodeBuilder identity : identities) { - final String baseIdentityName = identity.getBaseIdentityName(); - final int line = identity.getLine(); - if (baseIdentityName != null) { - - IdentitySchemaNodeBuilder result = null; - if (baseIdentityName.contains(":")) { - String[] splittedBase = baseIdentityName.split(":"); - if (splittedBase.length > 2) { - throw new YangParseException(module.getName(), line, - "Failed to parse identityref base: " + baseIdentityName); - } - String prefix = splittedBase[0]; - String name = splittedBase[1]; - ModuleBuilder dependentModule = findTargetModule(prefix, module, modules, context, line); - if (dependentModule != null) { - result = ParserUtils.findIdentity(dependentModule.getAddedIdentities(), name); - } - } else { - result = ParserUtils.findIdentity(module.getAddedIdentities(), baseIdentityName); - } - identity.setBaseIdentity(result); - } + private void resolveIdentity(final ModuleBuilder module, final IdentitySchemaNodeBuilder identity) { + final String baseIdentityName = identity.getBaseIdentityName(); + if (baseIdentityName != null) { + IdentitySchemaNodeBuilder result = null; + if (baseIdentityName.contains(":")) { + final int line = identity.getLine(); + String[] splittedBase = baseIdentityName.split(":"); + if (splittedBase.length > 2) { + throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + + baseIdentityName); } + String prefix = splittedBase[0]; + String name = splittedBase[1]; + ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(module, prefix); + result = BuilderUtils.findIdentity(dependentModule.getAddedIdentities(), name); + } else { + result = BuilderUtils.findIdentity(module.getAddedIdentities(), baseIdentityName); } + identity.setBaseIdentity(result); } } @@ -1181,34 +1048,23 @@ public final class YangParserImpl implements YangContextParser { * * @param modules * all loaded modules - * @param context - * SchemaContext containing already resolved modules or null if - * context is not available */ - private void resolveUsesTargetGrouping(final Map> modules, - final SchemaContext context) { + private void resolveUsesTargetGrouping(final Map> modules) { final List allUses = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { allUses.addAll(inner.getValue().getAllUsesNodes()); } } for (UsesNodeBuilder usesNode : allUses) { - ModuleBuilder module = ParserUtils.getParentModule(usesNode); + ModuleBuilder module = BuilderUtils.getParentModule(usesNode); final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); if (targetGroupingBuilder == null) { - if (context == null) { - throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '" - + usesNode.getGroupingPathAsString() + "' not found."); - } else { - GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode, - module, context); - usesNode.setGroupingDefinition(targetGroupingDefinition); - } - } else { - usesNode.setGrouping(targetGroupingBuilder); + throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '" + + usesNode.getGroupingPath() + "' not found."); } + usesNode.setGrouping(targetGroupingBuilder); } } @@ -1217,12 +1073,10 @@ public final class YangParserImpl implements YangContextParser { * * @param modules * all loaded modules - * @param context - * SchemaContext containing already resolved modules */ - private void resolveUsesForGroupings(final Map> modules, final SchemaContext context) { + private void resolveUsesForGroupings(final Map> modules) { final Set allGroupings = new HashSet<>(); - for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { ModuleBuilder module = inner.getValue(); allGroupings.addAll(module.getAllGroupings()); @@ -1233,7 +1087,7 @@ public final class YangParserImpl implements YangContextParser { List usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb)); Collections.sort(usesNodes, new GroupingUtils.UsesComparator()); for (UsesNodeBuilder usesNode : usesNodes) { - resolveUses(usesNode, modules, context); + resolveUses(usesNode, modules); } } } @@ -1243,17 +1097,15 @@ public final class YangParserImpl implements YangContextParser { * * @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()) { + private void resolveUsesForNodes(final Map> modules) { + for (Map.Entry> entry : modules.entrySet()) { for (Map.Entry inner : entry.getValue().entrySet()) { ModuleBuilder module = inner.getValue(); List usesNodes = module.getAllUsesNodes(); Collections.sort(usesNodes, new GroupingUtils.UsesComparator()); for (UsesNodeBuilder usesNode : usesNodes) { - resolveUses(usesNode, modules, context); + resolveUses(usesNode, modules); } } } @@ -1267,317 +1119,111 @@ public final class YangParserImpl implements YangContextParser { * 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) { + private void resolveUses(final UsesNodeBuilder usesNode, final Map> modules) { if (!usesNode.isResolved()) { DataNodeContainerBuilder parent = usesNode.getParent(); - ModuleBuilder module = ParserUtils.getParentModule(parent); + ModuleBuilder module = BuilderUtils.getParentModule(parent); GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); - if (target == null) { - resolveUsesWithContext(usesNode); - usesNode.setResolved(true); - for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { - 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.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); - usesNode.setResolved(true); - for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { - resolveUsesAugment(augment, module, modules, context); - } + + int index = nodeAfterUsesIndex(usesNode); + List targetNodes = target.instantiateChildNodes(parent); + for (DataSchemaNodeBuilder targetNode : targetNodes) { + parent.addChildNode(index++, targetNode); } + parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent)); + parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent)); + parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); + usesNode.setResolved(true); + for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { + resolveUsesAugment(augment, module, modules); + } + 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(); + private int nodeAfterUsesIndex(final UsesNodeBuilder usesNode) { 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(); + int usesLine = usesNode.getLine(); - Set childNodes = wrapChildNodes(module.getModuleName(), line, - gd.getChildNodes(), parentPath, ns, rev, pref); - parent.getChildNodeBuilders().addAll(childNodes); - for (DataSchemaNodeBuilder childNode : childNodes) { - setNodeAddedByUses(childNode); + List childNodes = parent.getChildNodeBuilders(); + if (childNodes.isEmpty()) { + return 0; } - Set typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, ns, - rev, pref); - parent.getTypeDefinitionBuilders().addAll(typedefs); - for (TypeDefinitionBuilder typedef : typedefs) { - setNodeAddedByUses(typedef); + DataSchemaNodeBuilder nextNodeAfterUses = null; + for (DataSchemaNodeBuilder childNode : childNodes) { + if (!(childNode.isAddedByUses()) && !(childNode.isAugmenting())) { + if (childNode.getLine() > usesLine) { + nextNodeAfterUses = childNode; + break; + } + } } - Set groupings = wrapGroupings(module.getModuleName(), line, usesNode - .getGroupingDefinition().getGroupings(), parentPath, ns, rev, pref); - parent.getGroupingBuilders().addAll(groupings); - for (GroupingBuilder gb : groupings) { - setNodeAddedByUses(gb); + // uses is declared after child nodes + if (nextNodeAfterUses == null) { + return childNodes.size(); } - List unknownNodes = wrapUnknownNodes(module.getModuleName(), line, - gd.getUnknownSchemaNodes(), parentPath, ns, rev, pref); - parent.getUnknownNodes().addAll(unknownNodes); - for (UnknownSchemaNodeBuilder un : unknownNodes) { - un.setAddedByUses(true); - } + return parent.getChildNodeBuilders().indexOf(nextNodeAfterUses); } /** - * Try to find extension builder describing this unknown node and assign it - * to unknown node builder. + * Try to find extension 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) { + 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.getAddedExtensions()) { - if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { - usnb.setNodeType(extension.getQName()); - usnb.setExtensionBuilder(extension); - break; - } - } - } catch (YangParseException e) { - throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb - + ": no such extension definition found.", e); + String localName = usnb.getNodeType().getLocalName(); + ModuleBuilder dependentModule = BuilderUtils.findModule(nodeType, modules); + + if (dependentModule == null) { + LOG.warn( + "Error in module {} at line {}: Failed to resolve node {}: no such extension definition found.", + module.getName(), usnb.getLine(), usnb); + continue; } - } - } - /** - * 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()) { - QName nodeType = usnb.getNodeType(); - try { - ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, nodeType.getPrefix(), - usnb.getLine()); - - if (dependentModuleBuilder == null) { - Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(), - usnb.getLine()); - for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) { - if (e.getQName().getLocalName().equals(nodeType.getLocalName())) { - usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(), - nodeType.getPrefix(), e.getQName().getLocalName())); - usnb.setExtensionDefinition(e); - break; - } - } + ExtensionBuilder extBuilder = findExtBuilder(localName, dependentModule.getAddedExtensions()); + if (extBuilder == null) { + ExtensionDefinition extDef = findExtDef(localName, dependentModule.getExtensions()); + if (extDef == null) { + LOG.warn( + "Error in module {} at line {}: Failed to resolve node {}: no such extension definition found.", + module.getName(), usnb.getLine(), usnb); } else { - for (ExtensionBuilder extension : dependentModuleBuilder.getAddedExtensions()) { - if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { - usnb.setExtensionBuilder(extension); - break; - } - } + usnb.setExtensionDefinition(extDef); } - - } catch (YangParseException e) { - throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb - + ": no such extension definition found.", e); - } - - } - } - - /** - * Traverse through modules and resolve their deviation statements. - * - * @param modules - * all loaded modules - */ - private void resolveDeviations(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder b = inner.getValue(); - resolveDeviation(modules, b); - } - } - } - - /** - * Traverse through module and resolve its deviation statements. - * - * @param modules - * all loaded modules - * @param module - * module in which resolve deviations - */ - private void resolveDeviation(final Map> modules, final ModuleBuilder module) { - for (DeviationBuilder dev : module.getDeviationBuilders()) { - int line = dev.getLine(); - SchemaPath targetPath = dev.getTargetPath(); - List path = targetPath.getPath(); - QName q0 = path.get(0); - String prefix = q0.getPrefix(); - if (prefix == null) { - prefix = module.getPrefix(); + } else { + usnb.setExtensionBuilder(extBuilder); } - - ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line); - processDeviation(dev, dependentModuleBuilder, path, module); } } - /** - * Traverse through modules and resolve their deviation statements with - * given context. - * - * @param modules - * all loaded modules - * @param context - * already resolved context - */ - private void resolveDeviationsWithContext(final Map> modules, - final SchemaContext context) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder b = inner.getValue(); - resolveDeviationWithContext(modules, b, context); + private ExtensionBuilder findExtBuilder(final String name, final Collection extensions) { + for (ExtensionBuilder extension : extensions) { + if (extension.getQName().getLocalName().equals(name)) { + return extension; } } + return null; } - /** - * Traverse through module and resolve its deviation statements with given - * context. - * - * @param modules - * all loaded modules - * @param module - * module in which resolve deviations - * @param context - * already resolved context - */ - private void resolveDeviationWithContext(final Map> modules, - final ModuleBuilder module, final SchemaContext context) { - for (DeviationBuilder dev : module.getDeviationBuilders()) { - int line = dev.getLine(); - SchemaPath targetPath = dev.getTargetPath(); - List path = targetPath.getPath(); - QName q0 = path.get(0); - String prefix = q0.getPrefix(); - if (prefix == null) { - prefix = module.getPrefix(); + private ExtensionDefinition findExtDef(final String name, final Collection extensions) { + for (ExtensionDefinition extension : extensions) { + if (extension.getQName().getLocalName().equals(name)) { + return extension; } - - ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line); - if (dependentModuleBuilder == null) { - Object currentParent = findModuleFromContext(context, module, prefix, line); - - for (QName q : path) { - if (currentParent == null) { - throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET); - } - String name = q.getLocalName(); - if (currentParent instanceof DataNodeContainer) { - currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name); - } - } - - if (currentParent == null) { - throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET); - } - if (currentParent instanceof SchemaNode) { - dev.setTargetPath(((SchemaNode) currentParent).getPath()); - } - - } else { - processDeviation(dev, dependentModuleBuilder, path, module); - } - } - } - - /** - * Correct deviation target path in deviation builder. - * - * @param dev - * deviation - * @param dependentModuleBuilder - * module containing deviation target - * @param path - * current deviation target path - * @param module - * current module - */ - private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder, - final List path, final ModuleBuilder module) { - final int line = dev.getLine(); - Builder currentParent = dependentModuleBuilder; - - for (QName q : path) { - if (currentParent == null) { - throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET); - } - String name = q.getLocalName(); - if (currentParent instanceof DataNodeContainerBuilder) { - currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name); - } - } - - if (!(currentParent instanceof SchemaNodeBuilder)) { - throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET); } - dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath()); + return null; } }