X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fsal%2Fyang-prototype%2Fcode-generator%2Fyang-model-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fyang%2Fparser%2Fimpl%2FYangParserImpl.java;h=e74029b424750b2b318f04df447fb7292a26c6cd;hp=85ca36791d79237615a6ec28d278d1b3ec1591c6;hb=f0b551cfbf794966124da7475935c27c3e7311c0;hpb=9090a5876e0540b12d30e4cdf29f8be25208b489 diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java index 85ca36791d..e74029b424 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.yang.parser.impl; +import static org.opendaylight.controller.yang.parser.util.ParserUtils.*; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -22,6 +24,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeMap; @@ -33,81 +36,150 @@ import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.opendaylight.controller.antlrv4.code.gen.YangLexer; import org.opendaylight.controller.antlrv4.code.gen.YangParser; import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.GroupingDefinition; +import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.ModuleImport; import org.opendaylight.controller.yang.model.api.SchemaContext; import org.opendaylight.controller.yang.model.api.SchemaPath; import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.LengthConstraint; -import org.opendaylight.controller.yang.model.api.type.PatternConstraint; -import org.opendaylight.controller.yang.model.api.type.RangeConstraint; -import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition; import org.opendaylight.controller.yang.model.parser.api.YangModelParser; import org.opendaylight.controller.yang.model.util.ExtendedType; import org.opendaylight.controller.yang.model.util.IdentityrefType; import org.opendaylight.controller.yang.model.util.UnknownType; import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder; -import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder; import org.opendaylight.controller.yang.parser.builder.api.Builder; -import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder; -import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder; +import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder; import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder; +import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder; import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder; import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder; import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder; import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder; -import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder; +import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder; import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder; import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder; import org.opendaylight.controller.yang.parser.util.ModuleDependencySort; -import org.opendaylight.controller.yang.parser.util.ParserUtils; import org.opendaylight.controller.yang.parser.util.RefineHolder; +import org.opendaylight.controller.yang.parser.util.RefineUtils; import org.opendaylight.controller.yang.parser.util.TypeConstraints; import org.opendaylight.controller.yang.parser.util.YangParseException; import org.opendaylight.controller.yang.validator.YangModelBasicValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class YangParserImpl implements YangModelParser { +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public final class YangParserImpl implements YangModelParser { - private static final Logger logger = LoggerFactory - .getLogger(YangParserImpl.class); + private static final Logger logger = LoggerFactory.getLogger(YangParserImpl.class); @Override public Set parseYangModels(final List yangFiles) { + return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values()); + } + + @Override + public Set parseYangModels(final List yangFiles, final SchemaContext context) { if (yangFiles != null) { - final List inputStreams = new ArrayList(); + final Map inputStreams = Maps.newHashMap(); for (final File yangFile : yangFiles) { try { - inputStreams.add(new FileInputStream(yangFile)); + inputStreams.put(new FileInputStream(yangFile), yangFile); } catch (FileNotFoundException e) { - logger.warn("Exception while reading yang file: " - + yangFile.getName(), e); + logger.warn("Exception while reading yang file: " + yangFile.getName(), e); } } - final Map> modules = resolveModuleBuilders(inputStreams); - return build(modules); + + Map builderToStreamMap = Maps.newHashMap(); + + final Map> modules = resolveModuleBuilders( + Lists.newArrayList(inputStreams.keySet()), builderToStreamMap); + + for (InputStream is : inputStreams.keySet()) { + try { + is.close(); + } catch (IOException e) { + logger.debug("Failed to close stream."); + } + } + + return new LinkedHashSet(buildWithContext(modules, context).values()); } return Collections.emptySet(); } @Override - public Set parseYangModelsFromStreams( - final List yangModelStreams) { - final Map> modules = resolveModuleBuilders(yangModelStreams); - return build(modules); + public Set parseYangModelsFromStreams(final List yangModelStreams) { + return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values()); + } + + @Override + public Set parseYangModelsFromStreams(final List yangModelStreams, SchemaContext context) { + if (yangModelStreams != null) { + Map builderToStreamMap = Maps.newHashMap(); + final Map> modules = resolveModuleBuildersWithContext( + yangModelStreams, builderToStreamMap, context); + return new LinkedHashSet(buildWithContext(modules, context).values()); + } + return Collections.emptySet(); + } + + @Override + public Map parseYangModelsMapped(List yangFiles) { + if (yangFiles != null) { + final Map inputStreams = Maps.newHashMap(); + + for (final File yangFile : yangFiles) { + try { + inputStreams.put(new FileInputStream(yangFile), yangFile); + } catch (FileNotFoundException e) { + logger.warn("Exception while reading yang file: " + yangFile.getName(), e); + } + } + + Map builderToStreamMap = Maps.newHashMap(); + final Map> modules = resolveModuleBuilders( + Lists.newArrayList(inputStreams.keySet()), builderToStreamMap); + + for (InputStream is : inputStreams.keySet()) { + try { + is.close(); + } catch (IOException e) { + logger.debug("Failed to close stream."); + } + } + + Map retVal = Maps.newLinkedHashMap(); + Map builderToModuleMap = build(modules); + + for (Entry builderToModule : builderToModuleMap.entrySet()) { + retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())), + builderToModule.getValue()); + } + + return retVal; + } + return Collections.emptyMap(); + } + + @Override + public Map parseYangModelsFromStreamsMapped(final List yangModelStreams) { + Map builderToStreamMap = Maps.newHashMap(); + + final Map> modules = resolveModuleBuilders(yangModelStreams, + builderToStreamMap); + Map retVal = Maps.newLinkedHashMap(); + Map builderToModuleMap = build(modules); + + for (Entry builderToModule : builderToModuleMap.entrySet()) { + retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue()); + } + return retVal; } @Override @@ -115,13 +187,11 @@ public class YangParserImpl implements YangModelParser { return new SchemaContextImpl(modules); } - private Map> resolveModuleBuilders( - final List yangFileStreams) { - // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER - // of items stored in map. - final Map> modules = new LinkedHashMap>(); + private ModuleBuilder[] parseModuleBuilders(List inputStreams, + Map streamToBuilderMap) { + final ParseTreeWalker walker = new ParseTreeWalker(); - final List trees = parseStreams(yangFileStreams); + final List trees = parseStreams(inputStreams); final ModuleBuilder[] builders = new ModuleBuilder[trees.size()]; // validate yang @@ -131,20 +201,47 @@ public class YangParserImpl implements YangModelParser { for (int i = 0; i < trees.size(); i++) { yangModelParser = new YangParserListenerImpl(); walker.walk(yangModelParser, trees.get(i)); - builders[i] = yangModelParser.getModuleBuilder(); + ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder(); + + // We expect the order of trees and streams has to be the same + streamToBuilderMap.put(moduleBuilder, inputStreams.get(i)); + builders[i] = moduleBuilder; } + return builders; + } + + private Map> resolveModuleBuilders(final List yangFileStreams, + Map streamToBuilderMap) { + return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null); + } + + private Map> resolveModuleBuildersWithContext( + final List yangFileStreams, final Map streamToBuilderMap, + final SchemaContext context) { + final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap); + + // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER + // of items stored in map. + final LinkedHashMap> modules = new LinkedHashMap>(); // module dependency graph sorted - List sorted = ModuleDependencySort.sort(builders); + List sorted = null; + if (context == null) { + sorted = ModuleDependencySort.sort(builders); + } else { + sorted = ModuleDependencySort.sortWithContext(context, builders); + } - for (ModuleBuilder builder : sorted) { + for (final ModuleBuilder builder : sorted) { + if (builder == null) { + continue; + } final String builderName = builder.getName(); Date builderRevision = builder.getRevision(); if (builderRevision == null) { builderRevision = new Date(0L); } - TreeMap builderByRevision = modules - .get(builderName); + TreeMap builderByRevision = modules.get(builderName); if (builderByRevision == null) { builderByRevision = new TreeMap(); } @@ -169,6 +266,9 @@ public class YangParserImpl implements YangModelParser { final YangLexer lexer = new YangLexer(input); final CommonTokenStream tokens = new CommonTokenStream(lexer); final YangParser parser = new YangParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new YangErrorListener()); + result = parser.yang(); } catch (IOException e) { logger.warn("Exception while reading yang file: " + yangStream, e); @@ -176,13 +276,10 @@ public class YangParserImpl implements YangModelParser { return result; } - private Set build( - final Map> modules) { + private Map build(final Map> modules) { // fix unresolved nodes - for (Map.Entry> entry : modules - .entrySet()) { - for (Map.Entry childEntry : entry.getValue() - .entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry childEntry : entry.getValue().entrySet()) { final ModuleBuilder moduleBuilder = childEntry.getValue(); fixUnresolvedNodes(modules, moduleBuilder); } @@ -190,33 +287,65 @@ public class YangParserImpl implements YangModelParser { resolveAugments(modules); // build - // Linked Hash Set MUST be used otherwise the Set will not maintain + // LinkedHashMap MUST be used otherwise the values will not maintain // order! - // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html - final Set result = new LinkedHashSet(); - for (Map.Entry> entry : modules - .entrySet()) { + // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html + final Map result = new LinkedHashMap(); + for (Map.Entry> entry : modules.entrySet()) { final Map modulesByRevision = new HashMap(); - for (Map.Entry childEntry : entry.getValue() - .entrySet()) { + for (Map.Entry childEntry : entry.getValue().entrySet()) { final ModuleBuilder moduleBuilder = childEntry.getValue(); final Module module = moduleBuilder.build(); modulesByRevision.put(childEntry.getKey(), module); - result.add(module); + result.put(moduleBuilder, module); } } return result; } - private void fixUnresolvedNodes( - final Map> modules, - final ModuleBuilder builder) { + private Map buildWithContext(final Map> modules, + SchemaContext context) { + // fix unresolved nodes + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry childEntry : entry.getValue().entrySet()) { + final ModuleBuilder moduleBuilder = childEntry.getValue(); + fixUnresolvedNodesWithContext(modules, moduleBuilder, context); + } + } + resolveAugmentsWithContext(modules, context); + + // build + // LinkedHashMap MUST be used otherwise the values will not maintain + // order! + // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html + final Map result = new LinkedHashMap(); + for (Map.Entry> entry : modules.entrySet()) { + final Map modulesByRevision = new HashMap(); + for (Map.Entry childEntry : entry.getValue().entrySet()) { + final ModuleBuilder moduleBuilder = childEntry.getValue(); + final Module module = moduleBuilder.build(); + modulesByRevision.put(childEntry.getKey(), module); + result.put(moduleBuilder, module); + } + } + return result; + } + + private void fixUnresolvedNodes(final Map> modules, final ModuleBuilder builder) { resolveDirtyNodes(modules, builder); resolveIdentities(modules, builder); - resolveUses(modules, builder); + resolveUsesRefine(modules, builder); resolveUnknownNodes(modules, builder); } + private void fixUnresolvedNodesWithContext(final Map> modules, + final ModuleBuilder builder, final SchemaContext context) { + resolveDirtyNodesWithContext(modules, builder, context); + resolveIdentitiesWithContext(modules, builder, context); + resolveUsesRefineWithContext(modules, builder, context); + resolveUnknownNodesWithContext(modules, builder, context); + } + /** * Search for dirty nodes (node which contains UnknownType) and resolve * unknown types. @@ -226,391 +355,264 @@ public class YangParserImpl implements YangModelParser { * @param module * current module */ - private void resolveDirtyNodes( - final Map> modules, - final ModuleBuilder module) { - final Map, TypeAwareBuilder> dirtyNodes = module - .getDirtyNodes(); + private void resolveDirtyNodes(final Map> modules, final ModuleBuilder module) { + final Map, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes(); if (!dirtyNodes.isEmpty()) { - for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes - .entrySet()) { - + for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes.entrySet()) { final TypeAwareBuilder nodeToResolve = entry.getValue(); - // different handling for union types + if (nodeToResolve instanceof UnionTypeBuilder) { - final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve; - final List> unionTypes = union.getTypes(); - final List toRemove = new ArrayList(); - for (TypeDefinition td : unionTypes) { - if (td instanceof UnknownType) { - final UnknownType unknownType = (UnknownType) td; - final TypeDefinitionBuilder resolvedType = resolveTypeUnion( - nodeToResolve, unknownType, modules, module); - union.setType(resolvedType); - toRemove.add(unknownType); - } - } - unionTypes.removeAll(toRemove); + // special handling for union types + resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module); } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { - IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve - .getTypedef(); - nodeToResolve.setType(new IdentityrefType(findFullQName( - modules, module, idref), idref.getPath())); + // special handling for identityref types + IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef(); + nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath())); } else { - final TypeDefinitionBuilder resolvedType = resolveType( - nodeToResolve, modules, module); - nodeToResolve.setType(resolvedType); + resolveType(nodeToResolve, modules, module); } } } } - private TypeDefinitionBuilder resolveType( - final TypeAwareBuilder typeToResolve, - final Map> modules, - final ModuleBuilder builder) { - final TypeConstraints constraints = new TypeConstraints(); - - final TypeDefinitionBuilder targetType = getTypedefBuilder( - typeToResolve, modules, builder); - final TypeConstraints tConstraints = findConstraints(typeToResolve, - constraints, modules, builder); - targetType.setRanges(tConstraints.getRange()); - targetType.setLengths(tConstraints.getLength()); - targetType.setPatterns(tConstraints.getPatterns()); - targetType.setFractionDigits(tConstraints.getFractionDigits()); - - return targetType; - } + private void resolveDirtyNodesWithContext(final Map> modules, + final ModuleBuilder module, SchemaContext context) { + final Map, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes(); + if (!dirtyNodes.isEmpty()) { + for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes.entrySet()) { + final TypeAwareBuilder nodeToResolve = entry.getValue(); - private TypeDefinitionBuilder resolveTypeUnion( - final TypeAwareBuilder typeToResolve, - final UnknownType unknownType, - final Map> modules, - final ModuleBuilder builder) { - final TypeConstraints constraints = new TypeConstraints(); - - final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve, - unknownType, modules, builder); - final TypeConstraints tConstraints = findConstraints(typeToResolve, - constraints, modules, builder); - targetType.setRanges(tConstraints.getRange()); - targetType.setLengths(tConstraints.getLength()); - targetType.setPatterns(tConstraints.getPatterns()); - targetType.setFractionDigits(tConstraints.getFractionDigits()); - - return targetType; - } - - private TypeDefinitionBuilder getTypedefBuilder( - final TypeAwareBuilder nodeToResolve, - final Map> modules, - final ModuleBuilder builder) { - - final TypeDefinition nodeToResolveBase = nodeToResolve.getType(); - if (nodeToResolveBase != null - && !(nodeToResolveBase instanceof UnknownType)) { - return (TypeDefinitionBuilder) nodeToResolve; - } - - final UnknownType unknownType = (UnknownType) nodeToResolve.getType(); - final QName unknownTypeQName = unknownType.getQName(); - - // search for module which contains referenced typedef - final ModuleBuilder dependentModule = findDependentModule(modules, - builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine()); - final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName( - dependentModule, unknownTypeQName.getLocalName(), - builder.getName(), nodeToResolve.getLine()); - - final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder( - lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder); - final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder( - lookedUpBuilderCopy, modules, dependentModule); - return resolvedCopy; - } - - private TypeDefinitionBuilder getUnionBuilder( - final TypeAwareBuilder nodeToResolve, - final UnknownType unknownType, - final Map> modules, - final ModuleBuilder module) { - - final TypeDefinition baseTypeToResolve = nodeToResolve.getType(); - if (baseTypeToResolve != null - && !(baseTypeToResolve instanceof UnknownType)) { - return (TypeDefinitionBuilder) nodeToResolve; - } - - final QName unknownTypeQName = unknownType.getQName(); - // search for module which contains referenced typedef - final ModuleBuilder dependentModule = findDependentModule(modules, - module, unknownTypeQName.getPrefix(), nodeToResolve.getLine()); - final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName( - dependentModule, unknownTypeQName.getLocalName(), - module.getName(), nodeToResolve.getLine()); - - final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder( - lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder); - final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder( - lookedUpBuilderCopy, modules, dependentModule); - return resolvedCopy; - } - - private TypeDefinitionBuilder copyTypedefBuilder( - final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) { - if (old instanceof UnionTypeBuilder) { - final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old; - final UnionTypeBuilder newUnion = new UnionTypeBuilder( - oldUnion.getActualPath(), oldUnion.getNamespace(), - oldUnion.getRevision(), old.getLine()); - for (TypeDefinition td : oldUnion.getTypes()) { - newUnion.setType(td); - } - for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) { - newUnion.setType(copyTypedefBuilder(tdb, true)); - } - return newUnion; - } - - final QName oldName = old.getQName(); - final QName newName = new QName(oldName.getNamespace(), - oldName.getRevision(), oldName.getPrefix(), - oldName.getLocalName()); - final TypeDefinitionBuilder tdb = new TypedefBuilder(newName, - old.getLine()); - - tdb.setRanges(old.getRanges()); - tdb.setLengths(old.getLengths()); - tdb.setPatterns(old.getPatterns()); - tdb.setFractionDigits(old.getFractionDigits()); - tdb.setPath(old.getPath()); - - final TypeDefinition oldType = old.getType(); - if (oldType == null) { - tdb.setType(old.getTypedef()); - } else { - tdb.setType(oldType); - } - - if (!seekByTypedefBuilder) { - tdb.setDescription(old.getDescription()); - tdb.setReference(old.getReference()); - tdb.setStatus(old.getStatus()); - tdb.setDefaultValue(old.getDefaultValue()); - tdb.setUnits(old.getUnits()); - } - return tdb; - } - - private TypeDefinitionBuilder resolveCopiedBuilder( - final TypeDefinitionBuilder copy, - final Map> modules, - final ModuleBuilder builder) { - - if (copy instanceof UnionTypeBuilder) { - final UnionTypeBuilder union = (UnionTypeBuilder) copy; - final List> unionTypes = union.getTypes(); - final List toRemove = new ArrayList(); - for (TypeDefinition td : unionTypes) { - if (td instanceof UnknownType) { - final UnknownType unknownType = (UnknownType) td; - final TypeDefinitionBuilder resolvedType = resolveTypeUnion( - union, unknownType, modules, builder); - union.setType(resolvedType); - toRemove.add(unknownType); + 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(); + nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath())); + } else { + resolveTypeWithContext(nodeToResolve, modules, module, context); } } - unionTypes.removeAll(toRemove); - - return union; - } - - final TypeDefinition base = copy.getType(); - final TypeDefinitionBuilder baseTdb = copy.getTypedef(); - if (base != null && !(base instanceof UnknownType)) { - return copy; - } else if (base instanceof UnknownType) { - final UnknownType unknownType = (UnknownType) base; - final QName unknownTypeQName = unknownType.getQName(); - final String unknownTypePrefix = unknownTypeQName.getPrefix(); - final ModuleBuilder dependentModule = findDependentModule(modules, - builder, unknownTypePrefix, copy.getLine()); - final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy, - modules, dependentModule); - copy.setType(utBuilder); - return copy; - } else if (base == null && baseTdb != null) { - // make a copy of baseTypeDef and call again - final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder( - baseTdb, true); - final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder( - baseTdbCopy, modules, builder); - copy.setType(baseTdbCopyResolved); - return copy; - } else { - throw new IllegalStateException("Failed to resolve type " - + copy.getQName().getLocalName()); - } - } - - private TypeDefinitionBuilder findTypedefBuilder( - final QName unknownTypeQName, - final Map> modules, - final ModuleBuilder builder, int line) { - // search for module which contains referenced typedef - final ModuleBuilder dependentModule = findDependentModule(modules, - builder, unknownTypeQName.getPrefix(), line); - final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName( - dependentModule, unknownTypeQName.getLocalName(), - builder.getName(), line); - return copyTypedefBuilder(lookedUpBuilder, true); - } - - private TypeConstraints findConstraints( - final TypeAwareBuilder nodeToResolve, - final TypeConstraints constraints, - final Map> modules, - final ModuleBuilder builder) { - // union type cannot be restricted - if (nodeToResolve instanceof UnionTypeBuilder) { - return constraints; - } - - // if referenced type is UnknownType again, search recursively with - // current constraints - final TypeDefinition referencedType = nodeToResolve.getType(); - List ranges = Collections.emptyList(); - List lengths = Collections.emptyList(); - List patterns = Collections.emptyList(); - Integer fractionDigits = null; - if (referencedType == null) { - final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef(); - ranges = tdb.getRanges(); - constraints.addRanges(ranges); - lengths = tdb.getLengths(); - constraints.addLengths(lengths); - patterns = tdb.getPatterns(); - constraints.addPatterns(patterns); - fractionDigits = tdb.getFractionDigits(); - constraints.setFractionDigits(fractionDigits); - return constraints; - } else if (referencedType instanceof ExtendedType) { - final ExtendedType ext = (ExtendedType) referencedType; - ranges = ext.getRanges(); - constraints.addRanges(ranges); - lengths = ext.getLengths(); - constraints.addLengths(lengths); - patterns = ext.getPatterns(); - constraints.addPatterns(patterns); - fractionDigits = ext.getFractionDigits(); - constraints.setFractionDigits(fractionDigits); - return findConstraints( - findTypedefBuilder(ext.getQName(), modules, builder, - nodeToResolve.getLine()), constraints, modules, - builder); - } else if (referencedType instanceof UnknownType) { - final UnknownType unknown = (UnknownType) referencedType; - ranges = unknown.getRangeStatements(); - constraints.addRanges(ranges); - lengths = unknown.getLengthStatements(); - constraints.addLengths(lengths); - patterns = unknown.getPatterns(); - constraints.addPatterns(patterns); - fractionDigits = unknown.getFractionDigits(); - constraints.setFractionDigits(fractionDigits); - - String unknownTypePrefix = unknown.getQName().getPrefix(); - if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) { - unknownTypePrefix = builder.getPrefix(); - } - final ModuleBuilder dependentModule = findDependentModule(modules, - builder, unknown.getQName().getPrefix(), - nodeToResolve.getLine()); - final TypeDefinitionBuilder utBuilder = findTypedefBuilder( - unknown.getQName(), modules, builder, - nodeToResolve.getLine()); - return findConstraints(utBuilder, constraints, modules, - dependentModule); - } else { - // HANDLE BASE YANG TYPE - mergeConstraints(referencedType, constraints); - return constraints; } } /** - * Search for type definition builder by name. + * Resolve unknown type of node. It is assumed that type of node is either + * UnknownType or ExtendedType with UnknownType as base type. * - * @param dependentModule - * module to search - * @param name - * name of type definition - * @param currentModuleName - * current module name - * @param line - * current line in yang model - * @return + * @param nodeToResolve + * node with type to resolve + * @param modules + * all loaded modules + * @param module + * current module */ - private TypeDefinitionBuilder findTypedefBuilderByName( - final ModuleBuilder dependentModule, final String name, - final String currentModuleName, final int line) { - final Set typedefs = dependentModule - .getModuleTypedefs(); - for (TypeDefinitionBuilder td : typedefs) { - if (td.getQName().getLocalName().equals(name)) { - return td; - } + private void resolveType(final TypeAwareBuilder nodeToResolve, + final Map> modules, final ModuleBuilder module) { + TypeDefinitionBuilder resolvedType = null; + final int line = nodeToResolve.getLine(); + final TypeDefinition nodeToResolveType = nodeToResolve.getType(); + final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName(); + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(), + line); + + final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve.getPath(), + dependentModule, unknownTypeQName.getLocalName(), module.getName(), line); + + if (nodeToResolveType instanceof ExtendedType) { + final ExtendedType extType = (ExtendedType) nodeToResolveType; + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType, + modules, module, nodeToResolve.getLine()); + resolvedType = newType; + } else { + resolvedType = targetTypeBuilder; } - throw new YangParseException(currentModuleName, line, "Target module '" - + dependentModule.getName() + "' does not contain typedef '" - + name + "'."); + + // validate constraints + final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, + new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null); + constraints.validateConstraints(); + + nodeToResolve.setTypedef(resolvedType); } /** - * Pull restriction from referenced type and add them to given constraints + * Resolve unknown type of node. It is assumed that type of node is either + * UnknownType or ExtendedType with UnknownType as base type. * - * @param referencedType - * @param constraints + * @param nodeToResolve + * node with type to resolve + * @param modules + * all loaded modules + * @param module + * current module + * @param context + * SchemaContext containing already resolved modules */ - private void mergeConstraints(final TypeDefinition referencedType, - final TypeConstraints constraints) { - - if (referencedType instanceof DecimalTypeDefinition) { - constraints.addRanges(((DecimalTypeDefinition) referencedType) - .getRangeStatements()); - constraints - .setFractionDigits(((DecimalTypeDefinition) referencedType) - .getFractionDigits()); - } else if (referencedType instanceof IntegerTypeDefinition) { - constraints.addRanges(((IntegerTypeDefinition) referencedType) - .getRangeStatements()); - } else if (referencedType instanceof StringTypeDefinition) { - constraints.addPatterns(((StringTypeDefinition) referencedType) - .getPatterns()); - constraints.addLengths(((StringTypeDefinition) referencedType) - .getLengthStatements()); - } else if (referencedType instanceof BinaryTypeDefinition) { - constraints.addLengths(((BinaryTypeDefinition) referencedType) - .getLengthConstraints()); + private void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve, + final Map> modules, final ModuleBuilder module, + final SchemaContext context) { + TypeDefinitionBuilder resolvedType = null; + final int line = nodeToResolve.getLine(); + final TypeDefinition nodeToResolveType = nodeToResolve.getType(); + final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName(); + final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, + unknownTypeQName.getPrefix(), line); + + if (dependentModuleBuilder == null) { + final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line); + final Set> types = dependentModule.getTypeDefinitions(); + final TypeDefinition type = findTypeByName(types, unknownTypeQName.getLocalName()); + + if (nodeToResolveType instanceof ExtendedType) { + final ExtendedType extType = (ExtendedType) nodeToResolveType; + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module, + nodeToResolve.getLine()); + + nodeToResolve.setTypedef(newType); + } else { + if(nodeToResolve instanceof TypeDefinitionBuilder) { + TypeDefinitionBuilder tdb = (TypeDefinitionBuilder)nodeToResolve; + TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context); + tdb.setLengths(tc.getLength()); + tdb.setPatterns(tc.getPatterns()); + tdb.setRanges(tc.getRange()); + tdb.setFractionDigits(tc.getFractionDigits()); + } + nodeToResolve.setType(type); + } + + } else { + final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve.getPath(), + dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line); + + if (nodeToResolveType instanceof ExtendedType) { + final ExtendedType extType = (ExtendedType) nodeToResolveType; + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType, + modules, module, nodeToResolve.getLine()); + resolvedType = newType; + } else { + resolvedType = targetTypeBuilder; + } + + // validate constraints + final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints( + module.getName(), nodeToResolve.getLine()), modules, module, context); + constraints.validateConstraints(); + + nodeToResolve.setTypedef(resolvedType); + } + } + + private void resolveTypeUnion(final UnionTypeBuilder union, + final Map> modules, final ModuleBuilder builder) { + + final List> unionTypes = union.getTypes(); + final List> toRemove = new ArrayList>(); + for (TypeDefinition unionType : unionTypes) { + if (unionType instanceof UnknownType) { + final UnknownType ut = (UnknownType) unionType; + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName() + .getPrefix(), union.getLine()); + final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union.getPath(), dependentModule, + ut.getQName().getLocalName(), builder.getName(), union.getLine()); + union.setTypedef(resolvedType); + toRemove.add(ut); + } else if (unionType instanceof ExtendedType) { + final ExtendedType extType = (ExtendedType) unionType; + final TypeDefinition extTypeBase = extType.getBaseType(); + if (extTypeBase instanceof UnknownType) { + final UnknownType ut = (UnknownType) extTypeBase; + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName() + .getPrefix(), union.getLine()); + final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union.getPath(), + dependentModule, ut.getQName().getLocalName(), builder.getName(), union.getLine()); + + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, + extType, modules, builder, union.getLine()); + + union.setTypedef(newType); + toRemove.add(extType); + } + } } + unionTypes.removeAll(toRemove); + } + + private void resolveTypeUnionWithContext(final UnionTypeBuilder union, + final Map> modules, final ModuleBuilder builder, + final SchemaContext context) { + + final List> unionTypes = union.getTypes(); + final List> toRemove = new ArrayList>(); + for (TypeDefinition unionType : unionTypes) { + if (unionType instanceof UnknownType) { + final UnknownType ut = (UnknownType) unionType; + final QName utQName = ut.getQName(); + final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder, + utQName.getPrefix(), union.getLine()); + + if (dependentModuleBuilder == null) { + Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(), + union.getLine()); + Set> types = dependentModule.getTypeDefinitions(); + TypeDefinition type = findTypeByName(types, utQName.getLocalName()); + union.setType(type); + toRemove.add(ut); + } else { + final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union.getPath(), + dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine()); + union.setTypedef(resolvedType); + toRemove.add(ut); + } + + } else if (unionType instanceof ExtendedType) { + final ExtendedType extType = (ExtendedType) unionType; + TypeDefinition extTypeBase = extType.getBaseType(); + if (extTypeBase instanceof UnknownType) { + final UnknownType ut = (UnknownType) extTypeBase; + final QName utQName = ut.getQName(); + final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder, + utQName.getPrefix(), union.getLine()); + + if (dependentModuleBuilder == null) { + final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(), + union.getLine()); + Set> types = dependentModule.getTypeDefinitions(); + TypeDefinition type = findTypeByName(types, utQName.getLocalName()); + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0); + + union.setTypedef(newType); + toRemove.add(extType); + } else { + final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union.getPath(), + dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine()); + + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, + extType, modules, builder, union.getLine()); + + union.setTypedef(newType); + toRemove.add(extType); + } + } + } + } + unionTypes.removeAll(toRemove); } /** - * Go through all augment definitions and resolve them. This method also - * finds augment target node and add child nodes to it. + * Go through all augment definitions and resolve them. It is expected that + * modules are already sorted by their dependencies. This method also finds + * augment target node and add child nodes to it. * * @param modules * all available modules */ - private void resolveAugments( - final Map> modules) { + private void resolveAugments(final Map> modules) { final List allModulesList = new ArrayList(); final Set allModulesSet = new HashSet(); - for (Map.Entry> entry : modules - .entrySet()) { - for (Map.Entry inner : entry.getValue() - .entrySet()) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { allModulesList.add(inner.getValue()); allModulesSet.add(inner.getValue()); } @@ -621,19 +623,15 @@ public class YangParserImpl implements YangModelParser { // try to resolve augments in module resolveAugment(modules, module); // while all augments are not resolved - final Iterator allModulesIterator = allModulesSet - .iterator(); - while (!(module.getAugmentsResolved() == module.getAddedAugments() - .size())) { + final Iterator allModulesIterator = allModulesSet.iterator(); + while (!(module.getAugmentsResolved() == module.getAugments().size())) { ModuleBuilder nextModule = null; // try resolve other module augments try { nextModule = allModulesIterator.next(); resolveAugment(modules, nextModule); } catch (NoSuchElementException e) { - throw new YangParseException( - "Failed to resolve augments in module '" - + module.getName() + "'.", e); + throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e); } // then try to resolve first module again resolveAugment(modules, module); @@ -642,22 +640,20 @@ public class YangParserImpl implements YangModelParser { } /** + * Tries to resolve augments in given module. If augment target node is not + * found, do nothing. * * @param modules * all available modules * @param module * current module */ - private void resolveAugment( - final Map> modules, - final ModuleBuilder module) { - if (module.getAugmentsResolved() < module.getAddedAugments().size()) { - for (AugmentationSchemaBuilder augmentBuilder : module - .getAddedAugments()) { + private void resolveAugment(final Map> modules, final ModuleBuilder module) { + if (module.getAugmentsResolved() < module.getAugments().size()) { + for (AugmentationSchemaBuilder augmentBuilder : module.getAugments()) { if (!augmentBuilder.isResolved()) { - final SchemaPath augmentTargetSchemaPath = augmentBuilder - .getTargetPath(); + final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath(); final List path = augmentTargetSchemaPath.getPath(); final QName qname = path.get(0); @@ -666,52 +662,91 @@ public class YangParserImpl implements YangModelParser { prefix = module.getPrefix(); } - DataSchemaNodeBuilder currentParent = null; - final ModuleBuilder dependentModule = findDependentModule( - modules, module, prefix, augmentBuilder.getLine()); - for (DataSchemaNodeBuilder child : dependentModule - .getChildNodes()) { - final QName childQName = child.getQName(); - if (childQName.getLocalName().equals( - qname.getLocalName())) { - currentParent = child; - break; - } - } + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, + augmentBuilder.getLine()); + processAugmentation(augmentBuilder, path, module, qname, dependentModule); + } - for (int i = 1; i < path.size(); i++) { - final QName currentQName = path.get(i); - DataSchemaNodeBuilder newParent = null; - for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent) - .getChildNodes()) { - final QName childQName = child.getQName(); - if (childQName.getLocalName().equals( - currentQName.getLocalName())) { - newParent = child; - break; - } - } - if (newParent == null) { - break; // node not found, quit search - } else { - currentParent = newParent; - } + } + } + } + + /** + * Go through all augment definitions and resolve them. This method works in + * same way as {@link #resolveAugments(Map)} except that if target node is not + * found in loaded modules, it search for target node in given context. + * + * @param modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules + */ + private void resolveAugmentsWithContext(final Map> modules, + final SchemaContext context) { + final List allModulesList = new ArrayList(); + final Set allModulesSet = new HashSet(); + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { + allModulesList.add(inner.getValue()); + allModulesSet.add(inner.getValue()); + } + } + + for (int i = 0; i < allModulesList.size(); i++) { + final ModuleBuilder module = allModulesList.get(i); + // try to resolve augments in module + resolveAugmentWithContext(modules, module, context); + // while all augments are not resolved + final Iterator allModulesIterator = allModulesSet.iterator(); + while (!(module.getAugmentsResolved() == module.getAugments().size())) { + ModuleBuilder nextModule = null; + // try resolve other module augments + try { + nextModule = allModulesIterator.next(); + resolveAugmentWithContext(modules, nextModule, context); + } catch (NoSuchElementException e) { + throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e); + } + // then try to resolve first module again + resolveAugmentWithContext(modules, module, context); + } + } + } + + /** + * Tries to resolve augments in given module. If augment target node is not + * found, do nothing. + * + * @param modules + * all available modules + * @param module + * current module + */ + private void resolveAugmentWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + if (module.getAugmentsResolved() < module.getAugments().size()) { + + for (AugmentationSchemaBuilder augmentBuilder : module.getAugments()) { + final int line = augmentBuilder.getLine(); + + if (!augmentBuilder.isResolved()) { + final List path = augmentBuilder.getTargetPath().getPath(); + final QName qname = path.get(0); + String prefix = qname.getPrefix(); + if (prefix == null) { + prefix = module.getPrefix(); } - final QName currentQName = currentParent.getQName(); - final QName lastAugmentPathElement = path - .get(path.size() - 1); - if (currentQName.getLocalName().equals( - lastAugmentPathElement.getLocalName())) { - ParserUtils.fillAugmentTarget(augmentBuilder, - (ChildNodeBuilder) currentParent); - ((AugmentationTargetBuilder) currentParent) - .addAugmentation(augmentBuilder); - SchemaPath oldPath = currentParent.getPath(); - augmentBuilder.setTargetPath(new SchemaPath(oldPath - .getPath(), oldPath.isAbsolute())); - augmentBuilder.setResolved(true); - module.augmentResolved(); + // try to find augment target module in loaded modules... + final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, + line); + if (dependentModuleBuilder == null) { + // perform augmentation on module from context and + // continue to next augment + processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context); + continue; + } else { + processAugmentation(augmentBuilder, path, module, qname, dependentModuleBuilder); } } @@ -728,11 +763,8 @@ public class YangParserImpl implements YangModelParser { * @param module * module being resolved */ - private void resolveIdentities( - final Map> modules, - final ModuleBuilder module) { - final Set identities = module - .getAddedIdentities(); + private void resolveIdentities(final Map> modules, final ModuleBuilder module) { + final Set identities = module.getIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { final String baseIdentityName = identity.getBaseIdentityName(); if (baseIdentityName != null) { @@ -746,14 +778,12 @@ public class YangParserImpl implements YangModelParser { baseIdentityPrefix = module.getPrefix(); baseIdentityLocalName = baseIdentityName; } - final ModuleBuilder dependentModule = findDependentModule( - modules, module, baseIdentityPrefix, identity.getLine()); + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix, + identity.getLine()); - final Set dependentModuleIdentities = dependentModule - .getAddedIdentities(); + final Set dependentModuleIdentities = dependentModule.getIdentities(); for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) { - if (idBuilder.getQName().getLocalName() - .equals(baseIdentityLocalName)) { + if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) { identity.setBaseIdentity(idBuilder); } } @@ -761,6 +791,59 @@ public class YangParserImpl implements YangModelParser { } } + /** + * 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 ModuleBuilder module, SchemaContext context) { + final Set identities = module.getIdentities(); + for (IdentitySchemaNodeBuilder identity : identities) { + final String baseIdentityName = identity.getBaseIdentityName(); + if (baseIdentityName != null) { + String baseIdentityPrefix = null; + String baseIdentityLocalName = null; + if (baseIdentityName.contains(":")) { + final String[] splitted = baseIdentityName.split(":"); + baseIdentityPrefix = splitted[0]; + baseIdentityLocalName = splitted[1]; + } else { + baseIdentityPrefix = module.getPrefix(); + baseIdentityLocalName = baseIdentityName; + } + final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, + baseIdentityPrefix, identity.getLine()); + + if (dependentModuleBuilder == null) { + final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix, + identity.getLine()); + final Set dependentModuleIdentities = dependentModule.getIdentities(); + for (IdentitySchemaNode idNode : dependentModuleIdentities) { + if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) { + identity.setBaseIdentity(idNode); + } + } + } else { + final Set dependentModuleIdentities = dependentModuleBuilder + .getIdentities(); + for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) { + if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) { + identity.setBaseIdentity(idBuilder); + } + } + } + } + } + } + /** * Go through uses statements defined in current module and resolve their * refine statements. @@ -770,244 +853,235 @@ public class YangParserImpl implements YangModelParser { * @param module * module being resolved */ - private void resolveUses( - final Map> modules, - final ModuleBuilder module) { - final Map, UsesNodeBuilder> moduleUses = module - .getAddedUsesNodes(); - for (Map.Entry, UsesNodeBuilder> entry : moduleUses - .entrySet()) { - final List key = entry.getKey(); + private void resolveUsesRefine(final Map> modules, final ModuleBuilder module) { + final Map, UsesNodeBuilder> moduleUses = module.getUsesNodes(); + for (Map.Entry, UsesNodeBuilder> entry : moduleUses.entrySet()) { final UsesNodeBuilder usesNode = entry.getValue(); final int line = usesNode.getLine(); + final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module); + usesNode.setGroupingPath(targetGrouping.getPath()); + for (RefineHolder refine : usesNode.getRefines()) { + final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping, + refine, module.getName()); + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); + } + } + } - final String groupingName = key.get(key.size() - 1); + /** + * Tries to search target grouping in given modules and resolve refine + * nodes. If grouping is not found in modules, method tries to find it in + * modules from context. + * + * @param modules + * all loaded modules + * @param module + * current module + * @param context + * SchemaContext containing already resolved modules + */ + private void resolveUsesRefineWithContext(final Map> modules, + final ModuleBuilder module, SchemaContext context) { + final Map, UsesNodeBuilder> moduleUses = module.getUsesNodes(); + for (Map.Entry, UsesNodeBuilder> entry : moduleUses.entrySet()) { + final UsesNodeBuilder usesNode = entry.getValue(); + final int line = usesNode.getLine(); - for (RefineHolder refine : usesNode.getRefines()) { - Builder refineTarget = getRefineNodeBuilderCopy(groupingName, - refine, modules, module); - ParserUtils.refineDefault(refineTarget, refine, line); - if (refineTarget instanceof LeafSchemaNodeBuilder) { - final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget; - ParserUtils.refineLeaf(leaf, refine, line); - usesNode.addRefineNode(leaf); - } else if (refineTarget instanceof ContainerSchemaNodeBuilder) { - final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget; - ParserUtils.refineContainer(container, refine, line); - usesNode.addRefineNode(container); - } else if (refineTarget instanceof ListSchemaNodeBuilder) { - final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget; - ParserUtils.refineList(list, refine, line); - usesNode.addRefineNode(list); - } else if (refineTarget instanceof LeafListSchemaNodeBuilder) { - final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineNodeBuilderCopy( - groupingName, refine, modules, module); - ParserUtils.refineLeafList(leafList, refine, line); - usesNode.addRefineNode(leafList); - } else if (refineTarget instanceof ChoiceBuilder) { - final ChoiceBuilder choice = (ChoiceBuilder) refineTarget; - ParserUtils.refineChoice(choice, refine, line); - usesNode.addRefineNode(choice); - } else if (refineTarget instanceof AnyXmlBuilder) { - final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget; - ParserUtils.refineAnyxml(anyXml, refine, line); - usesNode.addRefineNode(anyXml); + final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module); + if (targetGroupingBuilder == null) { + final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context); + usesNode.setGroupingPath(targetGrouping.getPath()); + for (RefineHolder refine : usesNode.getRefines()) { + final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingDefinition( + targetGrouping, refine, module.getName()); + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); + } + } else { + usesNode.setGroupingPath(targetGroupingBuilder.getPath()); + for (RefineHolder refine : usesNode.getRefines()) { + final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder( + targetGroupingBuilder, refine, module.getName()); + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); } } } } /** - * Find original builder of node to refine and return copy of this builder. - *

- * We must make a copy of builder to preserve original builder, because this - * object will be refined (modified) and later added to - * {@link UsesNodeBuilder}. - *

+ * Search given modules for grouping by name defined in uses node. * - * @param groupingPath - * path to grouping which contains node to refine - * @param refine - * refine object containing informations about refine + * @param usesBuilder + * builder of uses statement * @param modules * all loaded modules * @param module * current module - * @return copy of node to be refined if it is present in grouping, null - * otherwise + * @return grouping with given name if found, null otherwise */ - private Builder getRefineNodeBuilderCopy(final String groupingPath, - final RefineHolder refine, - final Map> modules, - final ModuleBuilder module) { - Builder result = null; - final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath, - refine, modules, module); - if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) { - result = ParserUtils - .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) { - result = ParserUtils - .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) { - result = ParserUtils - .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) { - result = ParserUtils - .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof ChoiceBuilder) { - result = ParserUtils - .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof AnyXmlBuilder) { - result = ParserUtils - .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder); + private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder, + final Map> modules, final ModuleBuilder module) { + final int line = usesBuilder.getLine(); + final String groupingString = usesBuilder.getGroupingName(); + String groupingPrefix; + String groupingName; + + if (groupingString.contains(":")) { + String[] splitted = groupingString.split(":"); + if (splitted.length != 2 || groupingString.contains("/")) { + throw new YangParseException(module.getName(), line, "Invalid name of target grouping"); + } + groupingPrefix = splitted[0]; + groupingName = splitted[1]; + } else { + groupingPrefix = module.getPrefix(); + groupingName = groupingString; + } + + ModuleBuilder dependentModule = null; + if (groupingPrefix.equals(module.getPrefix())) { + dependentModule = module; } else { - throw new YangParseException(module.getName(), refine.getLine(), - "Target '" + refine.getName() + "' can not be refined"); + dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line); + } + + if (dependentModule == null) { + return null; + } + + List path = usesBuilder.getPath().getPath(); + GroupingBuilder result = null; + Set groupings = dependentModule.getModuleGroupings(); + result = findGroupingBuilder(groupings, groupingName); + + if (result == null) { + Builder currentNode = null; + final List currentPath = new ArrayList(); + currentPath.add(dependentModule.getName()); + + for (int i = 0; i < path.size(); i++) { + QName qname = path.get(i); + currentPath.add(qname.getLocalName()); + currentNode = dependentModule.getModuleNode(currentPath); + + if (currentNode instanceof RpcDefinitionBuilder) { + groupings = ((RpcDefinitionBuilder) currentNode).getGroupings(); + } else if (currentNode instanceof DataNodeContainerBuilder) { + groupings = ((DataNodeContainerBuilder) currentNode).getGroupings(); + } else { + groupings = Collections.emptySet(); + } + + result = findGroupingBuilder(groupings, groupingName); + if (result != null) { + break; + } + } } + return result; } /** - * Find builder of refine node. + * Search context for grouping by name defined in uses node. * - * @param groupingPath - * path to grouping which contains node to refine - * @param refineNodeName - * name of node to be refined - * @param modules - * all loaded modules + * @param usesBuilder + * builder of uses statement * @param module * current module - * @return Builder object of refine node if it is present in grouping, null - * otherwise + * @param context + * SchemaContext containing already resolved modules + * @return grouping with given name if found, null otherwise */ - private Builder findRefineTargetBuilder(final String groupingPath, - final RefineHolder refine, - final Map> modules, - final ModuleBuilder module) { - final SchemaPath path = ParserUtils.parseUsesPath(groupingPath); - final List builderPath = new ArrayList(); - String prefix = null; - for (QName qname : path.getPath()) { - builderPath.add(qname.getLocalName()); - prefix = qname.getPrefix(); - } - if (prefix == null) { - prefix = module.getPrefix(); - } - - final ModuleBuilder dependentModule = findDependentModule(modules, - module, prefix, refine.getLine()); - builderPath.add(0, "grouping"); - builderPath.add(0, dependentModule.getName()); - final GroupingBuilder builder = (GroupingBuilder) dependentModule - .getNode(builderPath); - - return builder.getChildNode(refine.getName()); - } - - private QName findFullQName( - final Map> modules, - final ModuleBuilder module, final IdentityrefTypeBuilder idref) { + private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder, + final ModuleBuilder module, SchemaContext context) { + final int line = usesBuilder.getLine(); + String groupingString = usesBuilder.getGroupingName(); + String groupingPrefix; + String groupingName; + + if (groupingString.contains(":")) { + String[] splitted = groupingString.split(":"); + if (splitted.length != 2 || groupingString.contains("/")) { + throw new YangParseException(module.getName(), line, "Invalid name of target grouping"); + } + groupingPrefix = splitted[0]; + groupingName = splitted[1]; + } else { + groupingPrefix = module.getPrefix(); + groupingName = groupingString; + } + + Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line); + return findGroupingDefinition(dependentModule.getGroupings(), groupingName); + } + + private QName findFullQName(final Map> modules, final ModuleBuilder module, + final IdentityrefTypeBuilder idref) { QName result = null; String baseString = idref.getBaseString(); if (baseString.contains(":")) { String[] splittedBase = baseString.split(":"); if (splittedBase.length > 2) { - throw new YangParseException(module.getName(), idref.getLine(), - "Failed to parse identityref base: " + baseString); + throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: " + + baseString); } String prefix = splittedBase[0]; String name = splittedBase[1]; - ModuleBuilder dependentModule = findDependentModule(modules, - module, prefix, idref.getLine()); - result = new QName(dependentModule.getNamespace(), - dependentModule.getRevision(), prefix, name); + ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine()); + result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name); } else { - result = new QName(module.getNamespace(), module.getRevision(), - module.getPrefix(), baseString); + result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString); } return result; } - private void resolveUnknownNodes( - final Map> modules, - final ModuleBuilder module) { - for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) { + private void resolveUnknownNodes(final Map> modules, final ModuleBuilder module) { + for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) { QName nodeType = usnb.getNodeType(); - if (nodeType.getNamespace() == null - || nodeType.getRevision() == null) { + if (nodeType.getNamespace() == null || nodeType.getRevision() == null) { try { - ModuleBuilder dependentModule = findDependentModule( - modules, module, nodeType.getPrefix(), + ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(), usnb.getLine()); - QName newNodeType = new QName( - dependentModule.getNamespace(), - dependentModule.getRevision(), + QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), nodeType.getPrefix(), nodeType.getLocalName()); usnb.setNodeType(newNodeType); } catch (YangParseException e) { - logger.debug(module.getName(), usnb.getLine(), - "Failed to find unknown node type: " + nodeType); + logger.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType); } } } } - /** - * Find dependent module based on given prefix - * - * @param modules - * all available modules - * @param module - * current module - * @param prefix - * target module prefix - * @return - */ - private ModuleBuilder findDependentModule( - final Map> modules, - final ModuleBuilder module, final String prefix, final int line) { - ModuleBuilder dependentModule = null; - Date dependentModuleRevision = null; + private void resolveUnknownNodesWithContext(final Map> modules, + final ModuleBuilder module, SchemaContext context) { + for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getUnknownNodes()) { + QName nodeType = unknownNodeBuilder.getNodeType(); + if (nodeType.getNamespace() == null || nodeType.getRevision() == null) { + try { + ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, + nodeType.getPrefix(), unknownNodeBuilder.getLine()); + + QName newNodeType = null; + if (dependentModuleBuilder == null) { + Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(), + unknownNodeBuilder.getLine()); + newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), + nodeType.getPrefix(), nodeType.getLocalName()); + } else { + newNodeType = new QName(dependentModuleBuilder.getNamespace(), + dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName()); + } - if (prefix.equals(module.getPrefix())) { - dependentModule = module; - } else { - final ModuleImport dependentModuleImport = ParserUtils - .getModuleImport(module, prefix); - if (dependentModuleImport == null) { - throw new YangParseException(module.getName(), line, - "No import found with prefix '" + prefix + "'."); - } - final String dependentModuleName = dependentModuleImport - .getModuleName(); - dependentModuleRevision = dependentModuleImport.getRevision(); - - final TreeMap moduleBuildersByRevision = modules - .get(dependentModuleName); - if (moduleBuildersByRevision == null) { - throw new YangParseException(module.getName(), line, - "Failed to find dependent module '" - + dependentModuleName + "'."); - } - if (dependentModuleRevision == null) { - dependentModule = moduleBuildersByRevision.lastEntry() - .getValue(); - } else { - dependentModule = moduleBuildersByRevision - .get(dependentModuleRevision); + unknownNodeBuilder.setNodeType(newNodeType); + } catch (YangParseException e) { + logger.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: " + + nodeType); + } } } - - if (dependentModule == null) { - throw new YangParseException(module.getName(), line, - "Failed to find dependent module with prefix '" + prefix - + "' and revision '" + dependentModuleRevision - + "'."); - } - return dependentModule; } }