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=fdc8369f4ada260763c4fc4f2a88f906aa1f5d79;hb=40cc734f65f305ecb2d5d7e01b694e5e54f716e1;hp=1d0d48a7ddf2d7b5c034440d15f477c76b29e8fd;hpb=b655d5e1807cf5fca0f8a4c0ecc8da565bd923c7;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 1d0d48a7dd..fdc8369f4a 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 @@ -9,23 +9,20 @@ package org.opendaylight.yangtools.yang.parser.impl; import static com.google.common.base.Preconditions.checkNotNull; 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.findModuleFromBuilders; 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; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -36,11 +33,10 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.NavigableMap; 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; @@ -50,11 +46,17 @@ 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.common.QNameModule; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; 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; @@ -72,7 +74,6 @@ 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.GroupingUtils; import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder; @@ -91,8 +92,6 @@ import org.slf4j.LoggerFactory; @Immutable public final class YangParserImpl implements YangContextParser { private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class); - private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target."; - private static final Splitter COLON_SPLITTER = Splitter.on(':'); private static final YangParserImpl INSTANCE = new YangParserImpl(); public static YangParserImpl getInstance() { @@ -132,7 +131,7 @@ public final class YangParserImpl implements YangContextParser { } } - Map sourceToBuilder = parseSourcesToBuilders(sourceToFile.keySet()); + Map sourceToBuilder = parseSourcesToBuilders(sourceToFile.keySet(), null); ModuleBuilder main = sourceToBuilder.get(mainFileSource); List moduleBuilders = new ArrayList<>(); @@ -142,7 +141,7 @@ public final class YangParserImpl implements YangContextParser { // module builders sorted by dependencies List sortedBuilders = ModuleDependencySort.sort(resolved); - LinkedHashMap> modules = resolveModulesWithImports(sortedBuilders, null); + Map> modules = resolveModulesWithImports(sortedBuilders, null); Collection unsorted = build(modules).values(); Set result = new LinkedHashSet<>( ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); @@ -197,7 +196,7 @@ public final class YangParserImpl implements YangContextParser { @Override public SchemaContext parseSources(final Collection sources) throws IOException,YangSyntaxErrorException { - return assembleContext(parseYangModelSources(sources).values()); + return assembleContext(parseYangModelSources(sources, null).values()); } @Override @@ -219,7 +218,7 @@ public final class YangParserImpl implements YangContextParser { } final List sorted = resolveModuleBuilders(sources, context); - final Map> modules = resolveModulesWithImports(sorted, context); + final Map> modules = resolveModulesWithImports(sorted, context); final Set unsorted = new LinkedHashSet<>(build(modules).values()); if (context != null) { @@ -234,22 +233,22 @@ public final class YangParserImpl implements YangContextParser { return resolveSchemaContext(result); } - private static LinkedHashMap> resolveModulesWithImports(final List sorted, + private static Map> resolveModulesWithImports(final List sorted, final SchemaContext context) { - final LinkedHashMap> modules = orderModules(sorted); + final Map> modules = orderModules(sorted); for (ModuleBuilder module : sorted) { if (module != null) { for (ModuleImport imp : module.getImports().values()) { String prefix = imp.getPrefix(); - ModuleBuilder targetModule = findModuleFromBuilders(modules, module, prefix, 0); + 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); + NavigableMap map = modules.get(targetModule.getNamespace()); if (map == null) { map = new TreeMap<>(); map.put(targetModule.getRevision(), targetModule); - modules.put(targetModule.getName(), map); + modules.put(targetModule.getNamespace(), map); } else { map.put(targetModule.getRevision(), targetModule); } @@ -280,7 +279,7 @@ public final class YangParserImpl implements YangContextParser { Map byteSourceToModule; try { - byteSourceToModule = parseYangModelSources(byteSourceToFile.keySet()); + byteSourceToModule = parseYangModelSources(byteSourceToFile.keySet(), null); } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } @@ -310,7 +309,7 @@ public final class YangParserImpl implements YangContextParser { Map sourceToModule; try { - sourceToModule = parseYangModelSources(sourceToStream.keySet()); + sourceToModule = parseYangModelSources(sourceToStream.keySet(), null); } catch (IOException | YangSyntaxErrorException e) { throw new YangParseException("Failed to parse yang data", e); } @@ -334,10 +333,10 @@ public final class YangParserImpl implements YangContextParser { } public Collection buildModules(final Collection builders) { - List sorted = ModuleDependencySort.sort(builders); - Map> modules = resolveModulesWithImports(sorted, null); + Collection unsorted = resolveSubmodules(builders); + List sorted = ModuleDependencySort.sort(unsorted); + Map> modules = resolveModulesWithImports(sorted, null); Map builderToModule = build(modules); - return builderToModule.values(); } @@ -347,15 +346,15 @@ public final class YangParserImpl implements YangContextParser { return resolveSchemaContext(sorted); } - private Map parseYangModelSources(final Collection sources) throws IOException, YangSyntaxErrorException { + 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()); - Map> modules = resolveModulesWithImports(sorted, null); + Map> modules = resolveModulesWithImports(sorted, null); Map builderToModule = build(modules); Map builderToSource = HashBiMap.create(sourceToBuilder).inverse(); sorted = ModuleDependencySort.sort(builderToModule.keySet()); @@ -379,13 +378,13 @@ public final class YangParserImpl implements YangContextParser { * @throws YangSyntaxErrorException */ // TODO: remove ByteSource result after removing YangModelParser - private Map resolveSources(final Collection streams) throws IOException, YangSyntaxErrorException { - Map builders = parseSourcesToBuilders(streams); + private Map resolveSources(final Collection streams, final SchemaContext context) throws IOException, YangSyntaxErrorException { + Map builders = parseSourcesToBuilders(streams, context); return resolveSubmodules(builders); } - private Map parseSourcesToBuilders(final Collection sources) - throws IOException, YangSyntaxErrorException { + 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<>(); @@ -393,6 +392,8 @@ 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(); @@ -404,7 +405,7 @@ public final class YangParserImpl implements YangContextParser { path = stream.toString(); } } - yangModelParser = new YangParserListenerImpl(path); + yangModelParser = new YangParserListenerImpl(namespaceContext, path); walker.walk(yangModelParser, entry.getValue()); ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder(); moduleBuilder.setSource(source); @@ -415,24 +416,54 @@ public final class YangParserImpl implements YangContextParser { 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(); + NavigableMap 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(); + NavigableMap 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; } @@ -440,32 +471,43 @@ 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(final 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()) { + NavigableMap 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().isEmpty()) { + resolveSubmodules(submodule, submodules); } + addSubmoduleToModule(submodule, module); } - return modules; } private void addSubmoduleToModule(final ModuleBuilder submodule, final ModuleBuilder module) { + module.addSubmodule(submodule); submodule.setParent(module); module.getDirtyNodes().addAll(submodule.getDirtyNodes()); module.getImports().putAll(submodule.getImports()); @@ -500,7 +542,7 @@ public final class YangParserImpl implements YangContextParser { private List resolveModuleBuilders(final Collection yangFileStreams, final SchemaContext context) throws IOException, YangSyntaxErrorException { - Map parsedBuilders = resolveSources(yangFileStreams); + Map parsedBuilders = resolveSources(yangFileStreams, context); ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()]; parsedBuilders.values().toArray(builders); @@ -515,31 +557,34 @@ public final class YangParserImpl implements YangContextParser { } /** - * Order modules by name and revision. + * Order modules by namespace and revision. * * @param modules * topologically sorted modules - * @return modules ordered by name and revision + * @return modules ordered by namespace and revision */ - private static LinkedHashMap> orderModules(final List modules) { - final LinkedHashMap> result = new LinkedHashMap<>(); + private static Map> orderModules(final List modules) { + final Map> 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); + + NavigableMap builderByRevision = result.get(ns); if (builderByRevision == null) { builderByRevision = new TreeMap<>(); - builderByRevision.put(builderRevision, builder); - result.put(builderName, builderByRevision); + builderByRevision.put(rev, builder); + result.put(ns, builderByRevision); } else { - builderByRevision.put(builderRevision, builder); + builderByRevision.put(rev, builder); } + } return result; } @@ -561,7 +606,7 @@ public final class YangParserImpl implements YangContextParser { // if this is submodule, add parent to filtered and pick its imports if (main.isSubmodule()) { - TreeMap dependencies = new TreeMap<>(); + NavigableMap dependencies = new TreeMap<>(); for (ModuleBuilder mb : other) { if (mb.getName().equals(main.getBelongsTo())) { dependencies.put(mb.getRevision(), mb); @@ -581,11 +626,9 @@ public final class YangParserImpl implements YangContextParser { filterImports(builder, other, filtered); } } else { - if (mi.getRevision().equals(builder.getRevision())) { - if (!filtered.contains(builder)) { - filtered.add(builder); - filterImports(builder, other, filtered); - } + if (!filtered.contains(builder) && mi.getRevision().equals(builder.getRevision())) { + filtered.add(builder); + filterImports(builder, other, filtered); } } } @@ -660,7 +703,7 @@ 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); resolveUsesTargetGrouping(modules); @@ -668,11 +711,11 @@ public final class YangParserImpl implements YangContextParser { resolveUsesForNodes(modules); resolveAugments(modules); resolveIdentities(modules); - resolveDeviations(modules); + checkChoiceCasesForDuplicityQNames(modules); // 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(); @@ -688,8 +731,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); @@ -707,7 +750,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) { @@ -717,7 +760,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"); @@ -738,85 +781,58 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveAugmentsTargetPath(final Map> modules) { + 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); + 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 */ - private void setCorrectAugmentTargetPath(final Map> modules, - final AugmentationSchemaBuilder augment) { - ModuleBuilder module = BuilderUtils.getParentModule(augment); - final SchemaPath newSchemaPath; - + private void setCorrectAugmentTargetPath(final AugmentationSchemaBuilder augment) { Builder parent = augment.getParent(); + final SchemaPath targetNodeSchemaPath; + if (parent instanceof UsesNodeBuilder) { - DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent(); - - QName baseQName = usesParent.getQName(); - final QNameModule qnm; - String prefix; - if (baseQName == null) { - ModuleBuilder m = BuilderUtils.getParentModule(usesParent); - qnm = m.getQNameModule(); - prefix = m.getPrefix(); - } else { - qnm = baseQName.getModule(); - prefix = baseQName.getPrefix(); - } + targetNodeSchemaPath = findUsesAugmentTargetNodePath(((UsesNodeBuilder) parent).getParent(), augment); + } else { + targetNodeSchemaPath = augment.getTargetPath(); + } - SchemaPath s = usesParent.getPath(); - for (QName qn : augment.getTargetPath().getPathFromRoot()) { - s = s.createChild(QName.create(qnm, prefix, qn.getLocalName())); - } + for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { + correctPathForAugmentNodes(childNode, targetNodeSchemaPath); + } + } - newSchemaPath = s; + 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 { - final List newPath = new ArrayList<>(); - - for (QName qn : augment.getTargetPath().getPathFromRoot()) { - QNameModule qnm = module.getQNameModule(); - String localPrefix = qn.getPrefix(); - if (localPrefix != null && !localPrefix.isEmpty()) { - ModuleBuilder currentModule = BuilderUtils.getModuleByPrefix(module, localPrefix); - if (currentModule == null) { - throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix " - + localPrefix + " not found."); - } - qnm = currentModule.getQNameModule(); - } - newPath.add(QName.create(qnm, localPrefix, qn.getLocalName())); - } - - /* - * FIXME: this method of SchemaPath construction is highly ineffective. - * It would be great if we could actually dive into the context, - * find the actual target node and reuse its SchemaPath. Can we - * do that? - */ - newSchemaPath = SchemaPath.create(newPath, true); + qnm = parentQName.getModule(); } - augment.setTargetNodeSchemaPath(newSchemaPath); - for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { - correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath()); + SchemaPath path = usesParent.getPath(); + for (QName qname : augment.getTargetPath().getPathFromRoot()) { + path = path.createChild(QName.create(qnm, qname.getLocalName())); } + + return path; } /** @@ -853,11 +869,11 @@ public final class YangParserImpl implements YangContextParser { */ private void checkAugmentMandatoryNodes(final Collection augments) { for (AugmentationSchemaBuilder augment : augments) { - String augmentPrefix = augment.getTargetPath().getPathFromRoot().iterator().next().getPrefix(); + URI augmentTargetNs = augment.getTargetPath().getPathFromRoot().iterator().next().getNamespace(); + Date augmentTargetRev = augment.getTargetPath().getPathFromRoot().iterator().next().getRevision(); ModuleBuilder module = BuilderUtils.getParentModule(augment); - String modulePrefix = module.getPrefix(); - if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) { + if (augmentTargetNs.equals(module.getNamespace()) && augmentTargetRev.equals(module.getRevision())) { continue; } @@ -878,9 +894,9 @@ public final class YangParserImpl implements YangContextParser { * all loaded modules topologically sorted (based on dependencies * between each other) */ - private void resolveAugments(final Map> modules) { + 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()); } @@ -916,7 +932,7 @@ public final class YangParserImpl implements YangContextParser { * @return true if augment process succeed */ private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, - final Map> modules) { + final Map> modules) { if (augment.isResolved()) { return true; } @@ -924,7 +940,7 @@ public final class YangParserImpl implements YangContextParser { UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent(); DataNodeContainerBuilder parentNode = usesNode.getParent(); Optional potentialTargetNode; - SchemaPath resolvedTargetPath = augment.getTargetNodeSchemaPath(); + 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 @@ -939,7 +955,7 @@ public final class YangParserImpl implements YangContextParser { // since resolveUsesAugment occurs before augmenting from external // modules. potentialTargetNode = Optional. fromNullable(findSchemaNode(augment.getTargetPath() - .getPath(), (SchemaNodeBuilder) parentNode)); + .getPathFromRoot(), (SchemaNodeBuilder) parentNode)); } if (potentialTargetNode.isPresent()) { @@ -950,8 +966,12 @@ public final class YangParserImpl implements YangContextParser { augment.setResolved(true); return true; } else { - throw new YangParseException(module.getName(), augment.getLine(), String.format( - "Failed to resolve augment in uses. Invalid augment target: %s", potentialTargetNode)); + LOG.warn( + "Error in module {} at line {}: Unsupported augment target: {}. Augmentation process skipped.", + module.getName(), augment.getLine(), potentialTargetNode); + augment.setResolved(true); + augment.setUnsupportedTarget(true); + return true; } } else { throw new YangParseException(module.getName(), augment.getLine(), String.format( @@ -972,13 +992,13 @@ public final class YangParserImpl implements YangContextParser { * @return true if augment process succeed */ private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, - final Map> modules) { + final Map> modules) { if (augment.isResolved()) { return true; } QName targetModuleName = augment.getTargetPath().getPathFromRoot().iterator().next(); - ModuleBuilder targetModule = BuilderUtils.getModuleByPrefix(module, targetModuleName.getPrefix()); + ModuleBuilder targetModule = BuilderUtils.findModule(targetModuleName, modules); if (targetModule == null) { throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment " + augment); @@ -994,19 +1014,19 @@ public final class YangParserImpl implements YangContextParser { * @param modules * 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) { - resolveIdentity(modules, module, identity); + resolveIdentity(module, identity); } } } } - private void resolveIdentity(final Map> modules, final ModuleBuilder module, + private void resolveIdentity(final ModuleBuilder module, final IdentitySchemaNodeBuilder identity) { final String baseIdentityName = identity.getBaseIdentityName(); if (baseIdentityName != null) { @@ -1015,15 +1035,34 @@ public final class YangParserImpl implements YangContextParser { 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); + 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); + + if (prefix.equals(module.getPrefix()) + && name.equals(identity.getQName().getLocalName())) { + throw new YangParseException(module.getName(), + identity.getLine(), + "Failed to parse base, identity name equals base identity name: " + + baseIdentityName); + } + + ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix( + module, prefix); + result = BuilderUtils.findIdentity( + dependentModule.getAddedIdentities(), name); } else { - result = BuilderUtils.findIdentity(module.getAddedIdentities(), baseIdentityName); + if (baseIdentityName.equals(identity.getQName().getLocalName())) { + throw new YangParseException(module.getName(), + identity.getLine(), + "Failed to parse base, identity name equals base identity name: " + + baseIdentityName); + } + result = BuilderUtils.findIdentity(module.getAddedIdentities(), + baseIdentityName); } identity.setBaseIdentity(result); } @@ -1035,9 +1074,9 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveUsesTargetGrouping(final Map> modules) { + 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()); } @@ -1046,10 +1085,6 @@ public final class YangParserImpl implements YangContextParser { ModuleBuilder module = BuilderUtils.getParentModule(usesNode); final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); - if (targetGroupingBuilder == null) { - throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '" - + usesNode.getGroupingPathAsString() + "' not found."); - } usesNode.setGrouping(targetGroupingBuilder); } } @@ -1060,9 +1095,9 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveUsesForGroupings(final Map> modules) { + 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()); @@ -1084,8 +1119,8 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveUsesForNodes(final Map> modules) { - 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(); @@ -1106,7 +1141,7 @@ public final class YangParserImpl implements YangContextParser { * @param modules * all loaded modules */ - private void resolveUses(final UsesNodeBuilder usesNode, final Map> modules) { + private void resolveUses(final UsesNodeBuilder usesNode, final Map> modules) { if (!usesNode.isResolved()) { DataNodeContainerBuilder parent = usesNode.getParent(); ModuleBuilder module = BuilderUtils.getParentModule(parent); @@ -1140,11 +1175,9 @@ public final class YangParserImpl implements YangContextParser { DataSchemaNodeBuilder nextNodeAfterUses = null; for (DataSchemaNodeBuilder childNode : childNodes) { - if (!(childNode.isAddedByUses()) && !(childNode.isAugmenting())) { - if (childNode.getLine() > usesLine) { - nextNodeAfterUses = childNode; - break; - } + if (!childNode.isAddedByUses() && !childNode.isAugmenting() && childNode.getLine() > usesLine) { + nextNodeAfterUses = childNode; + break; } } @@ -1165,32 +1198,30 @@ public final class YangParserImpl implements YangContextParser { * @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(); - ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, nodeType.getPrefix()); - if (dependentModuleBuilder == null) { + 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; } - ExtensionBuilder extBuilder = findExtBuilder(nodeType.getLocalName(), - dependentModuleBuilder.getAddedExtensions()); + + ExtensionBuilder extBuilder = findExtBuilder(localName, dependentModule.getAddedExtensions()); if (extBuilder == null) { - ExtensionDefinition extDef = findExtDef(nodeType.getLocalName(), dependentModuleBuilder.getExtensions()); + 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 { - usnb.setNodeType(new QName(extDef.getQName().getNamespace(), extDef.getQName().getRevision(), - nodeType.getPrefix(), extDef.getQName().getLocalName())); usnb.setExtensionDefinition(extDef); } } else { - usnb.setNodeType(QName.create(extBuilder.getQName().getModule(), - nodeType.getPrefix(), extBuilder.getQName().getLocalName())); usnb.setExtensionBuilder(extBuilder); } } @@ -1214,74 +1245,73 @@ public final class YangParserImpl implements YangContextParser { return null; } + /** - * Traverse through modules and resolve their deviation statements. + * Traverse through modules and check if choice has choice cases with the + * same qname. * * @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); + private void checkChoiceCasesForDuplicityQNames(final Map> modules) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry childEntry : entry.getValue().entrySet()) { + final ModuleBuilder moduleBuilder = childEntry.getValue(); + final Module module = moduleBuilder.build(); + final List allChoicesFromModule = getChoicesFrom(module); + + for (ChoiceSchemaNode choiceNode : allChoicesFromModule) { + findDuplicityNodesIn(choiceNode, module, moduleBuilder, modules); + } } } } - /** - * 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()) { - SchemaPath targetPath = dev.getTargetPath(); - Iterable path = targetPath.getPathFromRoot(); - QName q0 = path.iterator().next(); - String prefix = q0.getPrefix(); - if (prefix == null) { - prefix = module.getPrefix(); + private void findDuplicityNodesIn(final ChoiceSchemaNode choiceNode, final Module module, final ModuleBuilder moduleBuilder, + final Map> modules) { + final Set duplicityTestSet = new HashSet<>(); + + for (ChoiceCaseNode choiceCaseNode : choiceNode.getCases()) { + + for (DataSchemaNode childSchemaNode : choiceCaseNode.getChildNodes()) { + if (!duplicityTestSet.add(childSchemaNode.getQName())) { + final Optional schemaNodeBuilder = BuilderUtils.findSchemaNodeInModule(childSchemaNode.getPath(), moduleBuilder); + final String nameOfSchemaNode = childSchemaNode.getQName().getLocalName(); + int lineOfSchemaNode = 0; + + if (schemaNodeBuilder.isPresent()) { + lineOfSchemaNode = schemaNodeBuilder.get().getLine(); + } + throw new YangParseException(module.getName(), lineOfSchemaNode, + String.format("Choice has two nodes case with same qnames - %s", nameOfSchemaNode)); + } } + } + } + + private List getChoicesFrom(final Module module) { + final List allChoices = new ArrayList<>(); - ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, prefix); - processDeviation(dev, dependentModuleBuilder, path, module); + for (DataSchemaNode dataSchemaNode : module.getChildNodes()) { + findChoicesIn(dataSchemaNode, allChoices); } + return allChoices; } - /** - * 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 Iterable 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); + private void findChoicesIn(final SchemaNode schemaNode, final Collection choiceNodes) { + if (schemaNode instanceof ContainerSchemaNode) { + final ContainerSchemaNode contSchemaNode = (ContainerSchemaNode) schemaNode; + for (DataSchemaNode dataSchemaNode : contSchemaNode.getChildNodes()) { + findChoicesIn(dataSchemaNode, choiceNodes); } - String name = q.getLocalName(); - if (currentParent instanceof DataNodeContainerBuilder) { - currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name); + } else if (schemaNode instanceof ListSchemaNode) { + final ListSchemaNode listSchemaNode = (ListSchemaNode) schemaNode; + for (DataSchemaNode dataSchemaNode : listSchemaNode.getChildNodes()) { + findChoicesIn(dataSchemaNode, choiceNodes); } + } else if (schemaNode instanceof ChoiceSchemaNode) { + choiceNodes.add((ChoiceSchemaNode) schemaNode); } - - if (!(currentParent instanceof SchemaNodeBuilder)) { - throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET); - } - dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath()); } + }