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=7d64b944219d122ad84d157cd383eb054bb02b10;hp=ac2b5334fb3ec66e0cf8915fee70101f5da2e8bc;hb=0df356fd6dd1e24f82a4afaa6c824517d354fb20;hpb=7e82c13539bf01ba2c00989ced01a96cb7a0214e 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 ac2b5334fb..7d64b94421 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,28 +36,33 @@ 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.AnyXmlSchemaNode; +import org.opendaylight.controller.yang.model.api.ChoiceNode; +import org.opendaylight.controller.yang.model.api.ContainerSchemaNode; +import org.opendaylight.controller.yang.model.api.DataNodeContainer; +import org.opendaylight.controller.yang.model.api.DataSchemaNode; +import org.opendaylight.controller.yang.model.api.GroupingDefinition; +import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; +import org.opendaylight.controller.yang.model.api.LeafListSchemaNode; +import org.opendaylight.controller.yang.model.api.LeafSchemaNode; +import org.opendaylight.controller.yang.model.api.ListSchemaNode; 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.SchemaNode; 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.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.api.UsesNode; 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.DataNodeContainerBuilder; import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder; +import org.opendaylight.controller.yang.parser.builder.api.GroupingMember; 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; @@ -62,6 +70,8 @@ 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.DeviationBuilder; +import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl; 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; @@ -72,44 +82,127 @@ import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl; import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder; import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder; +import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl; +import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl.UsesNodeImpl; 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 final class YangParserImpl implements YangModelParser { +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; - private static final Logger logger = LoggerFactory - .getLogger(YangParserImpl.class); +public final class YangParserImpl implements YangModelParser { + private static final Logger LOG = 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); + LOG.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) { + LOG.debug("Failed to close stream."); } } - final Map> modules = resolveModuleBuilders(inputStreams); - return build(modules); + + 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) { + LOG.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) { + LOG.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 @@ -117,13 +210,11 @@ public final 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 @@ -133,20 +224,47 @@ public final 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(); } @@ -171,54 +289,88 @@ public final 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); + LOG.warn("Exception while reading yang file: " + yangStream, e); } 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); } } resolveAugments(modules); + resolveDeviations(modules); + + // 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 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); + resolveDeviationsWithContext(modules, context); // build - // LinkedHashSet 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 void fixUnresolvedNodes(final Map> modules, final ModuleBuilder builder) { resolveDirtyNodes(modules, builder); resolveIdentities(modules, builder); - resolveUsesRefines(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. @@ -228,420 +380,335 @@ public final 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 Set dirtyNodes = module.getDirtyNodes(); if (!dirtyNodes.isEmpty()) { - for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes - .entrySet()) { - - final TypeAwareBuilder nodeToResolve = entry.getValue(); - // different handling for union types + for (TypeAwareBuilder nodeToResolve : dirtyNodes) { 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.setTypedef(resolvedType); - toRemove.add(unknownType); - } - } - unionTypes.removeAll(toRemove); + // special handling for union types + resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module); } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { - // different handling for identityref types - 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.setTypedef(resolvedType); + resolveType(nodeToResolve, modules, module); } } } } - private TypeDefinitionBuilder resolveType( - final TypeAwareBuilder nodeToResolve, - final Map> modules, - final ModuleBuilder builder) { - final TypeConstraints constraints = new TypeConstraints(); - - final TypeDefinitionBuilder targetTypeBuilder = getTypeDefinitionBuilderFromDirtyNode( - nodeToResolve, modules, builder); - final TypeConstraints tConstraints = findConstraints(nodeToResolve, - constraints, modules, builder); - targetTypeBuilder.setRanges(tConstraints.getRange()); - targetTypeBuilder.setLengths(tConstraints.getLength()); - targetTypeBuilder.setPatterns(tConstraints.getPatterns()); - targetTypeBuilder.setFractionDigits(tConstraints.getFractionDigits()); - - return targetTypeBuilder; - } - - private TypeDefinitionBuilder resolveTypeUnion( - final TypeAwareBuilder typeToResolve, - final UnknownType unknownType, - final Map> modules, - final ModuleBuilder builder) { - final TypeConstraints constraints = new TypeConstraints(); - - final TypeDefinitionBuilder targetTypeBuilder = getUnionBuilder( - typeToResolve, unknownType, modules, builder); - final TypeConstraints tConstraints = findConstraints(typeToResolve, - constraints, modules, builder); - targetTypeBuilder.setRanges(tConstraints.getRange()); - targetTypeBuilder.setLengths(tConstraints.getLength()); - targetTypeBuilder.setPatterns(tConstraints.getPatterns()); - targetTypeBuilder.setFractionDigits(tConstraints.getFractionDigits()); - - return targetTypeBuilder; - } - - private TypeDefinitionBuilder getTypeDefinitionBuilderFromDirtyNode( - final TypeAwareBuilder nodeToResolve, - final Map> modules, - final ModuleBuilder module) { - - final UnknownType unknownType = (UnknownType) nodeToResolve.getType(); - 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 = findTypeDefinitionBuilder( - nodeToResolve.getPath(), 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 void resolveDirtyNodesWithContext(final Map> modules, + final ModuleBuilder module, SchemaContext context) { + final Set dirtyNodes = module.getDirtyNodes(); + if (!dirtyNodes.isEmpty()) { + for (TypeAwareBuilder nodeToResolve : dirtyNodes) { + if (nodeToResolve instanceof UnionTypeBuilder) { + // special handling for union types + resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context); + } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { + // special handling for identityref types + IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef(); + nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath())); + } else { + resolveTypeWithContext(nodeToResolve, modules, module, context); + } + } + } } - 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; + /** + * Resolve unknown type of node. It is assumed that type of node is either + * UnknownType or ExtendedType with UnknownType as base type. + * + * @param nodeToResolve + * node with type to resolve + * @param modules + * all loaded modules + * @param module + * current module + */ + 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, 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; } - 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 = findTypeDefinitionBuilder( - nodeToResolve.getPath(), dependentModule, - unknownTypeQName.getLocalName(), module.getName(), - nodeToResolve.getLine()); - - final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder( - lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder); - final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder( - lookedUpBuilderCopy, modules, dependentModule); - return resolvedCopy; + // validate constraints + final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, + new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null); + constraints.validateConstraints(); + + nodeToResolve.setTypedef(resolvedType); } - private TypeDefinitionBuilder copyTypedefBuilder( - final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) { - if (old instanceof UnionTypeBuilder) { - final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old; - final UnionTypeBuilder newUnion = new UnionTypeBuilder( - old.getLine()); - for (TypeDefinition td : oldUnion.getTypes()) { - newUnion.setType(td); - } - for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) { - newUnion.setTypedef(copyTypedefBuilder(tdb, true)); + /** + * Resolve unknown type of node. It is assumed that type of node is either + * UnknownType or ExtendedType with UnknownType as base type. + * + * @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 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); } - newUnion.setPath(old.getPath()); - return newUnion; - } - final QName oldName = old.getQName(); - final QName newName = new QName(oldName.getNamespace(), - oldName.getRevision(), oldName.getPrefix(), - oldName.getLocalName()); - final TypeDefinitionBuilder tdb = new TypeDefinitionBuilderImpl( - 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.setTypedef(old.getTypedef()); } else { - tdb.setType(oldType); - } + final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, + 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(); - if (!seekByTypedefBuilder) { - tdb.setDescription(old.getDescription()); - tdb.setReference(old.getReference()); - tdb.setStatus(old.getStatus()); - tdb.setDefaultValue(old.getDefaultValue()); - tdb.setUnits(old.getUnits()); + nodeToResolve.setTypedef(resolvedType); } - 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.setTypedef(resolvedType); - toRemove.add(unknownType); + 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, 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, 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); - - 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 = getTypeDefinitionBuilderFromDirtyNode( - copy, modules, dependentModule); - copy.setTypedef(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.setTypedef(baseTdbCopyResolved); - return copy; - } else { - throw new YangParseException(copy.getLine(), - "Failed to resolve type " + copy.getQName().getLocalName()); } + unionTypes.removeAll(toRemove); } - 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; - } + 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, dependentModuleBuilder, + utQName.getLocalName(), builder.getName(), union.getLine()); + union.setTypedef(resolvedType); + toRemove.add(ut); + } - // 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( - findTypeDefinitionBuilder(nodeToResolve.getPath(), builder, - ext.getQName().getLocalName(), builder.getName(), - 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(); + } 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, + dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine()); + + final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, + extType, modules, builder, union.getLine()); + + union.setTypedef(newType); + toRemove.add(extType); + } + } } - final ModuleBuilder dependentModule = findDependentModule(modules, - builder, unknown.getQName().getPrefix(), - nodeToResolve.getLine()); - final TypeDefinitionBuilder utBuilder = findTypeDefinitionBuilder( - nodeToResolve.getPath(), dependentModule, unknown - .getQName().getLocalName(), builder.getName(), - nodeToResolve.getLine()); - return findConstraints(utBuilder, constraints, modules, - dependentModule); - } else { - // HANDLE BASE YANG TYPE - mergeConstraints(referencedType, constraints); - return constraints; } + unionTypes.removeAll(toRemove); } /** - * Search for type definition builder by name. + * 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 dirtyNodeSchemaPath - * schema path of node which contains unresolved type - * @param dependentModule - * module which should contains referenced type - * @param typeName - * name of type definition - * @param currentModuleName - * name of current module - * @param line - * current line in yang model - * @return + * @param modules + * all available modules */ - private TypeDefinitionBuilder findTypeDefinitionBuilder( - SchemaPath dirtyNodeSchemaPath, - final ModuleBuilder dependentModule, final String typeName, - final String currentModuleName, final int line) { - final List path = dirtyNodeSchemaPath.getPath(); - TypeDefinitionBuilder result = null; - - Set typedefs = dependentModule - .getModuleTypedefs(); - result = findTdb(typedefs, typeName); - - 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) { - typedefs = ((RpcDefinitionBuilder) currentNode) - .getTypeDefinitions(); - } else if (currentNode instanceof DataNodeContainerBuilder) { - typedefs = ((DataNodeContainerBuilder) currentNode) - .getTypeDefinitions(); - } else { - typedefs = Collections.emptySet(); - } - - result = findTdb(typedefs, typeName); - if (result != null) { - break; - } + 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()) { + allModulesList.add(inner.getValue()); + allModulesSet.add(inner.getValue()); } } - if (result != null) { - return result; - } - throw new YangParseException(currentModuleName, line, - "Referenced type '" + typeName + "' not found."); - } - - private TypeDefinitionBuilder findTdb(Set types, - String name) { - for (TypeDefinitionBuilder td : types) { - if (td.getQName().getLocalName().equals(name)) { - return td; + for (int i = 0; i < allModulesList.size(); i++) { + final ModuleBuilder module = allModulesList.get(i); + // try to resolve augments in module + resolveAugment(modules, module); + // while all augments are not resolved + final Iterator allModulesIterator = allModulesSet.iterator(); + while (!(module.getAugmentsResolved() == module.getAllAugments().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); + } + // then try to resolve first module again + resolveAugment(modules, module); } } - return null; } /** - * Pull restriction from referenced type and add them to given constraints + * Tries to resolve augments in given module. If augment target node is not + * found, do nothing. * - * @param referencedType - * @param constraints + * @param modules + * all available modules + * @param module + * current module */ - 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 resolveAugment(final Map> modules, final ModuleBuilder module) { + if (module.getAugmentsResolved() < module.getAllAugments().size()) { + for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) { + + if (!augmentBuilder.isResolved()) { + final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath(); + final List path = augmentTargetSchemaPath.getPath(); + + final QName qname = path.get(0); + String prefix = qname.getPrefix(); + if (prefix == null) { + prefix = module.getPrefix(); + } + + final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, + augmentBuilder.getLine()); + processAugmentation(augmentBuilder, path, module, dependentModule); + } + + } } } /** - * 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. 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 available modules + * all loaded modules + * @param context + * SchemaContext containing already resolved modules */ - private void resolveAugments( - final Map> 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()) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { allModulesList.add(inner.getValue()); allModulesSet.add(inner.getValue()); } @@ -650,109 +717,58 @@ public final class YangParserImpl implements YangModelParser { for (int i = 0; i < allModulesList.size(); i++) { final ModuleBuilder module = allModulesList.get(i); // try to resolve augments in module - resolveAugment(modules, module); + resolveAugmentWithContext(modules, module, context); // while all augments are not resolved - final Iterator allModulesIterator = allModulesSet - .iterator(); - while (!(module.getAugmentsResolved() == module.getAugments() - .size())) { + final Iterator allModulesIterator = allModulesSet.iterator(); + while (!(module.getAugmentsResolved() == module.getAllAugments().size())) { ModuleBuilder nextModule = null; // try resolve other module augments try { nextModule = allModulesIterator.next(); - resolveAugment(modules, nextModule); + resolveAugmentWithContext(modules, nextModule, context); } 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); + 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 resolveAugment( - final Map> modules, - final ModuleBuilder module) { - if (module.getAugmentsResolved() < module.getAugments().size()) { - for (AugmentationSchemaBuilder augmentBuilder : module - .getAugments()) { + private void resolveAugmentWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + if (module.getAugmentsResolved() < module.getAllAugments().size()) { - if (!augmentBuilder.isResolved()) { - final SchemaPath augmentTargetSchemaPath = augmentBuilder - .getTargetPath(); - final List path = augmentTargetSchemaPath.getPath(); + for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) { + 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(); } - 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; - } - } - - if (currentParent == null) { + // 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; - } - - for (int i = 1; i < path.size(); i++) { - final QName currentQName = path.get(i); - DataSchemaNodeBuilder newParent = null; - for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) 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; - } - } - - final QName currentQName = currentParent.getQName(); - final QName lastAugmentPathElement = path - .get(path.size() - 1); - if (currentQName.getLocalName().equals( - lastAugmentPathElement.getLocalName())) { - - if(currentParent instanceof ChoiceBuilder) { - ParserUtils.fillAugmentTarget(augmentBuilder, - (ChoiceBuilder) currentParent); - } else { - ParserUtils.fillAugmentTarget(augmentBuilder, - (DataNodeContainerBuilder) currentParent); - } - ((AugmentationTargetBuilder) currentParent) - .addAugmentation(augmentBuilder); - SchemaPath oldPath = currentParent.getPath(); - augmentBuilder.setTargetPath(new SchemaPath(oldPath - .getPath(), oldPath.isAbsolute())); - augmentBuilder.setResolved(true); - module.augmentResolved(); + } else { + processAugmentation(augmentBuilder, path, module, dependentModuleBuilder); } } @@ -769,11 +785,8 @@ public final class YangParserImpl implements YangModelParser { * @param module * module being resolved */ - private void resolveIdentities( - final Map> modules, - final ModuleBuilder module) { - final Set identities = module - .getIdentities(); + 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) { @@ -787,14 +800,12 @@ public final 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 - .getIdentities(); + final Set dependentModuleIdentities = dependentModule.getIdentities(); for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) { - if (idBuilder.getQName().getLocalName() - .equals(baseIdentityLocalName)) { + if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) { identity.setBaseIdentity(idBuilder); } } @@ -802,6 +813,59 @@ public final 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, final 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. @@ -811,275 +875,502 @@ public final class YangParserImpl implements YangModelParser { * @param module * module being resolved */ - private void resolveUsesRefines( - final Map> modules, - final ModuleBuilder module) { - final Map, UsesNodeBuilder> moduleUses = module - .getUsesNodes(); - for (Map.Entry, UsesNodeBuilder> entry : moduleUses - .entrySet()) { - final List key = entry.getKey(); - final UsesNodeBuilder usesNode = entry.getValue(); + private void resolveUsesRefine(final Map> modules, final ModuleBuilder module) { + final List allModuleUses = module.getAllUsesNodes(); + for (UsesNodeBuilder usesNode : allModuleUses) { + // refine final int line = usesNode.getLine(); - - final String groupingName = key.get(key.size() - 1); - + final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module); + usesNode.setGroupingPath(targetGrouping.getPath()); for (RefineHolder refine : usesNode.getRefines()) { - SchemaNodeBuilder refineTarget = getRefineNodeBuilderCopy( - groupingName, refine, modules, module); - ParserUtils.checkRefine(refineTarget, refine); - 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) refineTarget; - 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); - } else if (refineTarget instanceof GroupingBuilder) { - usesNode.addRefineNode(refineTarget); - } else if (refineTarget instanceof TypeDefinitionBuilder) { - usesNode.addRefineNode(refineTarget); + final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping, + refine, module.getName()); + if (nodeToRefine instanceof GroupingMember) { + ((GroupingMember) nodeToRefine).setAddedByUses(true); } + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); } + + // child nodes + processUsesNode(usesNode, targetGrouping); } } /** - * Find original builder of node to refine and return copy of this builder. - *

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

+ * 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 groupingPath - * path to grouping which contains node to refine - * @param refine - * refine object containing informations about refine * @param modules * all loaded modules * @param module * current module - * @return copy of node to be refined if it is present in grouping, null - * otherwise + * @param context + * SchemaContext containing already resolved modules */ - private SchemaNodeBuilder 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); - } else if (lookedUpBuilder instanceof GroupingBuilder) { - result = ParserUtils - .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder); - } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) { - result = ParserUtils - .copyTypedefBuilder((TypeDefinitionBuilderImpl) lookedUpBuilder); - } else { - throw new YangParseException(module.getName(), refine.getLine(), - "Target '" + refine.getName() + "' can not be refined"); + private void resolveUsesRefineWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + final List moduleUses = module.getAllUsesNodes(); + for (UsesNodeBuilder usesNode : moduleUses) { + final int line = usesNode.getLine(); + + 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()); + if (nodeToRefine instanceof GroupingMember) { + ((GroupingMember) nodeToRefine).setAddedByUses(true); + } + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); + } + + processUsesNode(usesNode, targetGrouping); + } else { + usesNode.setGroupingPath(targetGroupingBuilder.getPath()); + for (RefineHolder refine : usesNode.getRefines()) { + final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder( + targetGroupingBuilder, refine, module.getName()); + if (nodeToRefine instanceof GroupingMember) { + ((GroupingMember) nodeToRefine).setAddedByUses(true); + } + RefineUtils.performRefine(nodeToRefine, refine, line); + usesNode.addRefineNode(nodeToRefine); + } + + processUsesNode(usesNode, targetGroupingBuilder); + } } - return (SchemaNodeBuilder) result; } /** - * Find builder of refine node. + * Search given modules for grouping by name defined in uses node. * - * @param groupingPath - * path to grouping which contains node to refine - * @param refine - * object containing refine information + * @param usesBuilder + * builder of uses statement * @param modules * all loaded modules * @param module * current module - * @return Builder object of refine node if it is present in grouping, null - * otherwise + * @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 String refineNodeName = refine.getName(); - 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(); + 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 { + dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line); + } + + if (dependentModule == null) { + return null; } - if (prefix == null) { - prefix = module.getPrefix(); + + GroupingBuilder result = null; + Set groupings = dependentModule.getGroupingBuilders(); + result = findGroupingBuilder(groupings, groupingName); + if (result != null) { + return result; } - final ModuleBuilder dependentModule = findDependentModule(modules, - module, prefix, refine.getLine()); - builderPath.add(0, dependentModule.getName()); - final GroupingBuilder builder = dependentModule - .getGrouping(builderPath); + Builder parent = usesBuilder.getParent(); + + while (parent != null) { + if (parent instanceof DataNodeContainerBuilder) { + groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders(); + } else if (parent instanceof RpcDefinitionBuilder) { + groupings = ((RpcDefinitionBuilder) parent).getGroupings(); + } + result = findGroupingBuilder(groupings, groupingName); + if (result == null) { + parent = parent.getParent(); + } else { + break; + } + } - Builder result = builder.getChildNode(refineNodeName); if (result == null) { - Set grps = builder.getGroupings(); - for (GroupingBuilder gr : grps) { - if (gr.getQName().getLocalName().equals(refineNodeName)) { - result = gr; - break; + throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName + + "' not found."); + } + return result; + } + + /** + * Search context for grouping by name defined in uses node. + * + * @param usesBuilder + * builder of uses statement + * @param module + * current module + * @param context + * SchemaContext containing already resolved modules + * @return grouping with given name if found, null otherwise + */ + private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder, + final ModuleBuilder module, final 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); + } + + /** + * Add nodes defined in target grouping to current context. + * + * @param usesNode + * @param targetGrouping + */ + private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) { + List refineNodes = usesNode.getRefineNodes(); + DataNodeContainerBuilder parent = usesNode.getParent(); + SchemaPath parentPath = parent.getPath(); + for (DataSchemaNodeBuilder child : targetGrouping.getChildNodeBuilders()) { + if (child != null) { + // if node is refined, take it from refined nodes and continue + SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes); + if (refined != null) { + refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName())); + parent.addChildNode((DataSchemaNodeBuilder) refined); + continue; + } + + DataSchemaNodeBuilder newChild = null; + if (child instanceof AnyXmlBuilder) { + newChild = new AnyXmlBuilder((AnyXmlBuilder) child); + } else if (child instanceof ChoiceBuilder) { + newChild = new ChoiceBuilder((ChoiceBuilder) child); + } else if (child instanceof ContainerSchemaNodeBuilder) { + newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child); + } else if (child instanceof LeafListSchemaNodeBuilder) { + newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child); + } else if (child instanceof LeafSchemaNodeBuilder) { + newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child); + } else if (child instanceof ListSchemaNodeBuilder) { + newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child); } + + if (newChild == null) { + throw new YangParseException(usesNode.getLine(), + "Unknown member of target grouping while resolving uses node."); + } + + if (newChild instanceof GroupingMember) { + ((GroupingMember) newChild).setAddedByUses(true); + } + + newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName())); + parent.addChildNode(newChild); } } - if (result == null) { - Set typedefs = builder.getTypeDefinitions(); - for (TypeDefinitionBuilder typedef : typedefs) { - if (typedef.getQName().getLocalName().equals(refineNodeName)) { - result = typedef; - break; + for (GroupingBuilder g : targetGrouping.getGroupingBuilders()) { + GroupingBuilder newGrouping = new GroupingBuilderImpl(g); + newGrouping.setAddedByUses(true); + newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName())); + parent.addGrouping(newGrouping); + } + for (TypeDefinitionBuilder td : targetGrouping.getTypeDefinitionBuilders()) { + TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td); + newType.setAddedByUses(true); + newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName())); + parent.addTypedef(newType); + } + for (UsesNodeBuilder un : targetGrouping.getUses()) { + UsesNodeBuilder newUses = new UsesNodeBuilderImpl(un); + newUses.setAddedByUses(true); + // uses has not path + parent.addUsesNode(newUses); + } + for (UnknownSchemaNodeBuilder un : targetGrouping.getUnknownNodeBuilders()) { + UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un); + newUn.setAddedByUses(true); + newUn.setPath(createSchemaPath(parentPath, un.getQName().getLocalName())); + parent.addUnknownNodeBuilder(newUn); + } + } + + private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) { + final int line = usesNode.getLine(); + List refineNodes = usesNode.getRefineNodes(); + DataNodeContainerBuilder parent = usesNode.getParent(); + SchemaPath parentPath = parent.getPath(); + for (DataSchemaNode child : targetGrouping.getChildNodes()) { + if (child != null) { + // if node is refined, take it from refined nodes and continue + SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes); + if (refined != null) { + refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName())); + parent.addChildNode((DataSchemaNodeBuilder) refined); + continue; + } + + DataSchemaNodeBuilder newChild = null; + if (child instanceof AnyXmlSchemaNode) { + newChild = createAnyXml((AnyXmlSchemaNode) child, line); + } else if (child instanceof ChoiceNode) { + newChild = createChoice((ChoiceNode) child, line); + } else if (child instanceof ContainerSchemaNode) { + newChild = createContainer((ContainerSchemaNode) child, line); + } else if (child instanceof LeafListSchemaNode) { + newChild = createLeafList((LeafListSchemaNode) child, line); + } else if (child instanceof LeafSchemaNode) { + newChild = createLeafBuilder((LeafSchemaNode) child, line); + } else if (child instanceof ListSchemaNode) { + newChild = createList((ListSchemaNode) child, line); + } + + if (newChild == null) { + throw new YangParseException(usesNode.getLine(), + "Unknown member of target grouping while resolving uses node."); } + + if (newChild instanceof GroupingMember) { + ((GroupingMember) newChild).setAddedByUses(true); + } + newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName())); + parent.addChildNode(newChild); } } - return result; + for (GroupingDefinition g : targetGrouping.getGroupings()) { + GroupingBuilder newGrouping = createGrouping(g, line); + newGrouping.setAddedByUses(true); + newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName())); + parent.addGrouping(newGrouping); + } + for (TypeDefinition td : targetGrouping.getTypeDefinitions()) { + TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, line); + newType.setAddedByUses(true); + newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName())); + parent.addTypedef(newType); + } + for (UsesNode un : targetGrouping.getUses()) { + if (un instanceof UsesNodeImpl) { + UsesNodeBuilder newUses = new UsesNodeBuilderImpl(((UsesNodeImpl) un).toBuilder()); + newUses.setAddedByUses(true); + // uses has not path + parent.addUsesNode(newUses); + } + } + for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) { + UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, line); + newNode.setAddedByUses(true); + newNode.setPath(createSchemaPath(parentPath, un.getQName().getLocalName())); + parent.addUnknownNodeBuilder(newNode); + } } - private QName findFullQName( - final Map> modules, - final ModuleBuilder module, final IdentityrefTypeBuilder idref) { + 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.getUnknownNodes()) { + private void resolveUnknownNodes(final Map> modules, final ModuleBuilder module) { + for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) { 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); + LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType); + } + } + } + } + + private void resolveUnknownNodesWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) { + 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()); + } + + unknownNodeBuilder.setNodeType(newNodeType); + } catch (YangParseException e) { + LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: " + + nodeType); + } + } + } + } + + 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 resolveDeviation(final Map> modules, final ModuleBuilder module) { + for (DeviationBuilder dev : module.getDeviations()) { + int line = dev.getLine(); + SchemaPath targetPath = dev.getTargetPath(); + List path = targetPath.getPath(); + QName q0 = path.get(0); + String prefix = q0.getPrefix(); + if (prefix == null) { + prefix = module.getPrefix(); + } + + ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line); + processDeviation(dev, dependentModuleBuilder, path, module); + } + } + + private void resolveDeviationsWithContext(final Map> modules, + final SchemaContext context) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { + ModuleBuilder b = inner.getValue(); + resolveDeviationWithContext(modules, b, context); + } + } + } + + private void resolveDeviationWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + for (DeviationBuilder dev : module.getDeviations()) { + int line = dev.getLine(); + SchemaPath targetPath = dev.getTargetPath(); + List path = targetPath.getPath(); + QName q0 = path.get(0); + String prefix = q0.getPrefix(); + if (prefix == null) { + prefix = module.getPrefix(); + } + String name = null; + + ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line); + if (dependentModuleBuilder == null) { + Module dependentModule = findModuleFromContext(context, module, prefix, line); + Object currentParent = dependentModule; + + for (int i = 0; i < path.size(); i++) { + if (currentParent == null) { + throw new YangParseException(module.getName(), line, "Failed to find deviation target."); + } + QName q = path.get(i); + name = q.getLocalName(); + if (currentParent instanceof DataNodeContainer) { + currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name); + } + } + + if (currentParent == null) { + throw new YangParseException(module.getName(), line, "Failed to find deviation target."); + } + if (currentParent instanceof SchemaNode) { + dev.setTargetPath(((SchemaNode) currentParent).getPath()); } + + } else { + processDeviation(dev, dependentModuleBuilder, path, module); } } } /** - * Find dependent module based on given prefix + * Correct deviation target path in deviation builder. * - * @param modules - * all available modules + * @param dev + * deviation + * @param dependentModuleBuilder + * module containing deviation target + * @param path + * current deviation target path * @param module * current module - * @param prefix - * target module prefix - * @param line - * current line in yang model - * @return */ - private ModuleBuilder findDependentModule( - final Map> modules, - final ModuleBuilder module, final String prefix, final int line) { - ModuleBuilder dependentModule = null; - Date dependentModuleRevision = null; - - 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 + "'."); + private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder, + final List path, final ModuleBuilder module) { + final int line = dev.getLine(); + Builder currentParent = dependentModuleBuilder; + + for (int i = 0; i < path.size(); i++) { + if (currentParent == null) { + throw new YangParseException(module.getName(), line, "Failed to find deviation target."); } - 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); + QName q = path.get(i); + String name = q.getLocalName(); + if (currentParent instanceof DataNodeContainerBuilder) { + currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name); } } - if (dependentModule == null) { - throw new YangParseException(module.getName(), line, - "Failed to find dependent module with prefix '" + prefix - + "' and revision '" + dependentModuleRevision - + "'."); + if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) { + throw new YangParseException(module.getName(), line, "Failed to find deviation target."); } - return dependentModule; + dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath()); } }