From 502d44ae3d818dcabf4841058bbbf9dc4b9a1cff Mon Sep 17 00:00:00 2001 From: Martin Vitez Date: Mon, 13 Jan 2014 11:06:22 +0100 Subject: [PATCH] Added support for parsing submodules & added dependency utility parser All nodes defined in submodule are added to module to which submodule belongs. Dependency utility parser is small YANG parser which extracts module identifier (module name,revision) and all imports / includes, so it is easier for implementations using YANG parser to check if all dependencies are available. Change-Id: If1c4c5544aaf54e9ba7d8000a6f31cce83a7f9f1 Signed-off-by: Martin Vitez Signed-off-by: Tony Tkaciik --- .../binding/generator/impl/RefineTest.java | 4 +- .../yangtools/yang/common/QName.java | 26 +- .../AbstractCachingSchemaSourceProvider.java | 35 ++- .../repo/FilesystemSchemaCachingProvider.java | 22 +- .../model/util/repo/SchemaSourceProvider.java | 4 +- .../util/repo/SchemaSourceProviders.java | 45 +++ .../model/util/repo/SourceIdentifier.java | 78 +++++ .../api/AbstractDataNodeContainerBuilder.java | 17 +- .../builder/api/DataNodeContainerBuilder.java | 7 +- .../builder/impl/GroupingBuilderImpl.java | 2 +- .../parser/builder/impl/ModuleBuilder.java | 78 ++++- .../yang/parser/impl/YangParserImpl.java | 156 ++++++++-- .../parser/impl/YangParserListenerImpl.java | 35 +++ .../impl/util/YangModelDependencyInfo.java | 274 ++++++++++++++++++ .../parser/impl/util/YangSourceContext.java | 254 ++++++++++++++++ .../yangtools/yang/parser/util/CopyUtils.java | 20 +- .../yang/parser/util/GroupingSort.java | 4 +- .../yang/parser/util/GroupingUtils.java | 3 + .../yang/parser/util/ParserListenerUtils.java | 26 +- .../yang/parser/util/ParserUtils.xtend | 30 +- .../yang/parser/impl/YangParserTest.java | 26 ++ .../test/resources/submodule-test/subfoo.yang | 67 +++++ 22 files changed, 1118 insertions(+), 95 deletions(-) create mode 100644 yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java create mode 100644 yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang diff --git a/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/RefineTest.java b/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/RefineTest.java index 851794ac4d..bfd51620fe 100644 --- a/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/RefineTest.java +++ b/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/RefineTest.java @@ -74,7 +74,7 @@ public class RefineTest { loadTestResources(); assertEquals("Incorrect number of test files.", 1, testModels.size()); - Set usesNodeBuilders = getModuleBuilder().getUsesNodes(); + Set usesNodeBuilders = getModuleBuilder().getUsesNodeBuilders(); List refineHolders = null; Set dataSchemaNodeBuilders = null; for (UsesNodeBuilder usesNodeBuilder : usesNodeBuilders) { @@ -82,7 +82,7 @@ public class RefineTest { refineHolders = usesNodeBuilder.getRefines(); // FIXME //GroupingUtils.updateUsesParent(usesNodeBuilder); - dataSchemaNodeBuilders = usesNodeBuilder.getParent().getChildNodes(); + dataSchemaNodeBuilders = usesNodeBuilder.getParent().getChildNodeBuilders(); break; } } diff --git a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java index f52b21495a..01b20a3b54 100644 --- a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java +++ b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java @@ -13,6 +13,7 @@ import java.net.URISyntaxException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Objects; import org.opendaylight.yangtools.concepts.Immutable; import org.slf4j.Logger; @@ -238,11 +239,9 @@ public final class QName implements Immutable,Serializable { public static QName create(String namespace, String revision, String localName) throws IllegalArgumentException{ try { URI namespaceUri = new URI(namespace); - Date revisionDate = REVISION_FORMAT.get().parse(revision); + Date revisionDate = parseRevision(revision); return create(namespaceUri, revisionDate, localName); - } catch (ParseException pe) { - throw new IllegalArgumentException("Revision is not in supported format", pe); - } catch (URISyntaxException ue) { + } catch (URISyntaxException ue) { throw new IllegalArgumentException("Namespace is is not valid URI", ue); } } @@ -301,4 +300,23 @@ public final class QName implements Immutable,Serializable { public QName withoutRevision() { return QName.create(namespace, null, localName); } + + public static Date parseRevision(String formatedDate) { + try { + return REVISION_FORMAT.get().parse(formatedDate); + } catch (ParseException e) { + throw new IllegalArgumentException("Revision is not in supported format",e); + } + } + + public static String formattedRevision(Date revision) { + if(revision == null) { + return null; + } + return REVISION_FORMAT.get().format(revision); + } + + public boolean isEqualWithoutRevision(QName other) { + return localName.equals(other.getLocalName()) && Objects.equals(namespace, other.getNamespace()); + } } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/AbstractCachingSchemaSourceProvider.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/AbstractCachingSchemaSourceProvider.java index 021531e21f..ae03a49e00 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/AbstractCachingSchemaSourceProvider.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/AbstractCachingSchemaSourceProvider.java @@ -18,25 +18,31 @@ public abstract class AbstractCachingSchemaSourceProvider implements Schem @Override public Optional getSchemaSource(String moduleName, Optional revision) { - return getSchemaSourceImpl(moduleName, revision, defaultDelegate); + checkNotNull(moduleName, "Module name should not be null."); + checkNotNull(revision, "Revision should not be null"); + return getSchemaSource(SourceIdentifier.create(moduleName, revision)); + } + + @Override + public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + return getSchemaSourceImpl(sourceIdentifier, defaultDelegate); } - private Optional getSchemaSourceImpl(String moduleName, Optional revision, + protected final Optional getSchemaSourceImpl(SourceIdentifier identifier, SchemaSourceProvider delegate) { - checkNotNull(moduleName, "Module name should not be null."); - checkNotNull(revision, "Revision should not be null"); + checkNotNull(identifier, "Source identifier name should not be null."); - Optional cached = getCachedSchemaSource(moduleName, revision); + Optional cached = getCachedSchemaSource(identifier); if (cached.isPresent()) { return cached; } - Optional live = delegate.getSchemaSource(moduleName, revision); - return cacheSchemaSource(moduleName, revision, live); + Optional live = delegate.getSchemaSource(identifier); + return cacheSchemaSource(identifier, live); } - abstract protected Optional cacheSchemaSource(String moduleName, Optional revision, Optional stream); + abstract protected Optional cacheSchemaSource(SourceIdentifier identifier, Optional stream); - abstract protected Optional getCachedSchemaSource(String moduleName, Optional revision); + abstract protected Optional getCachedSchemaSource(SourceIdentifier identifier); public SchemaSourceProvider getDelegate() { return defaultDelegate; @@ -47,7 +53,9 @@ public abstract class AbstractCachingSchemaSourceProvider implements Schem return new SchemaSourceProviderInstance(delegate); } - private class SchemaSourceProviderInstance implements SchemaSourceProvider, Delegator> { + private class SchemaSourceProviderInstance implements // + SchemaSourceProvider, + Delegator> { private final SchemaSourceProvider delegate; @@ -58,12 +66,17 @@ public abstract class AbstractCachingSchemaSourceProvider implements Schem @Override public Optional getSchemaSource(String moduleName, Optional revision) { - return getSchemaSourceImpl(moduleName, revision, getDelegate()); + return getSchemaSource(SourceIdentifier.create(moduleName, revision)); } @Override public SchemaSourceProvider getDelegate() { return delegate; } + + @Override + public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + return getSchemaSourceImpl(sourceIdentifier, getDelegate()); + } } } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/FilesystemSchemaCachingProvider.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/FilesystemSchemaCachingProvider.java index 0fdf05a227..7794f1d2e3 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/FilesystemSchemaCachingProvider.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/FilesystemSchemaCachingProvider.java @@ -26,8 +26,8 @@ public class FilesystemSchemaCachingProvider extends AbstractCachingSchemaSou } @Override - protected synchronized Optional cacheSchemaSource(String moduleName, Optional revision, Optional source) { - File schemaFile = toFile(moduleName, revision); + protected synchronized Optional cacheSchemaSource(SourceIdentifier identifier, Optional source) { + File schemaFile = toFile(identifier); try { if(source.isPresent() && schemaFile.createNewFile()) { try ( @@ -59,8 +59,8 @@ public class FilesystemSchemaCachingProvider extends AbstractCachingSchemaSou } @Override - protected Optional getCachedSchemaSource(String moduleName, Optional revision) { - File inputFile = toFile(moduleName, revision); + protected Optional getCachedSchemaSource(SourceIdentifier identifier) { + File inputFile = toFile(identifier); try { if (inputFile.exists() && inputFile.canRead()) { InputStream stream = new FileInputStream(inputFile); @@ -72,19 +72,11 @@ public class FilesystemSchemaCachingProvider extends AbstractCachingSchemaSou return Optional.absent(); } - private File toFile(String moduleName, Optional revision) { - return new File(storageDirectory, toYangFileName(moduleName, revision)); + private File toFile(SourceIdentifier identifier) { + return new File(storageDirectory, identifier.toYangFilename()); } - public static final String toYangFileName(String moduleName, Optional revision) { - StringBuilder filename = new StringBuilder(moduleName); - if (revision.isPresent()) { - filename.append("@"); - filename.append(revision.get()); - } - filename.append(".yang"); - return filename.toString(); - } + private static final Function NOOP_TRANSFORMATION = new Function() { @Override diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProvider.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProvider.java index f8f6efbc83..eeb59ae3a9 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProvider.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProvider.java @@ -1,11 +1,11 @@ package org.opendaylight.yangtools.yang.model.util.repo; -import java.io.InputStream; - import com.google.common.base.Optional; public interface SchemaSourceProvider { Optional getSchemaSource(String moduleName, Optional revision); + + Optional getSchemaSource(SourceIdentifier sourceIdentifier); } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProviders.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProviders.java index 78cb713969..dbed32c7d5 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProviders.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProviders.java @@ -1,5 +1,10 @@ package org.opendaylight.yangtools.yang.model.util.repo; +import java.io.InputStream; +import java.io.StringBufferInputStream; + +import org.opendaylight.yangtools.concepts.Delegator; + import com.google.common.base.Optional; public class SchemaSourceProviders { @@ -12,6 +17,11 @@ public class SchemaSourceProviders { return Optional.absent(); } + @Override + public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + return Optional.absent(); + } + }; @SuppressWarnings("unchecked") @@ -19,4 +29,39 @@ public class SchemaSourceProviders { return (SchemaSourceProvider) NOOP_PROVIDER; } + public static SchemaSourceProvider inputStreamProviderfromStringProvider( + SchemaSourceProvider delegate) { + return new StringToInputStreamSchemaSourceProvider(delegate); + } + + private final static class StringToInputStreamSchemaSourceProvider implements // + SchemaSourceProvider, Delegator> { + + private SchemaSourceProvider delegate; + + public StringToInputStreamSchemaSourceProvider(SchemaSourceProvider delegate) { + this.delegate = delegate; + } + + @Override + public SchemaSourceProvider getDelegate() { + return delegate; + } + + @Override + public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + Optional potential = getDelegate().getSchemaSource(sourceIdentifier); + if (potential.isPresent()) { + String stringStream = potential.get(); + return Optional. of(new StringBufferInputStream(stringStream)); + } + return Optional.absent(); + } + + @Override + public Optional getSchemaSource(String moduleName, Optional revision) { + return getSchemaSource(SourceIdentifier.create(moduleName, revision)); + } + } + } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java new file mode 100644 index 0000000000..9105765d78 --- /dev/null +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java @@ -0,0 +1,78 @@ +package org.opendaylight.yangtools.yang.model.util.repo; + +import com.google.common.base.Optional; + +public final class SourceIdentifier { + + private final String name; + private final String revision; + + public SourceIdentifier(String name, Optional formattedRevision) { + super(); + this.name = name; + this.revision = formattedRevision.orNull(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((revision == null) ? 0 : revision.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SourceIdentifier other = (SourceIdentifier) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (revision == null) { + if (other.revision != null) + return false; + } else if (!revision.equals(other.revision)) + return false; + return true; + } + + public String getName() { + return name; + } + + public String getRevision() { + return revision; + } + + public static SourceIdentifier create(String moduleName, Optional revision) { + return new SourceIdentifier(moduleName, revision); + } + + public String toYangFilename() { + return toYangFileName(name, Optional.fromNullable(revision)); + } + + @Override + public String toString() { + return "SourceIdentifier [name=" + name + "@" + revision + "]"; + } + + public static final String toYangFileName(String moduleName, Optional revision) { + StringBuilder filename = new StringBuilder(moduleName); + if (revision.isPresent()) { + filename.append("@"); + filename.append(revision.get()); + } + filename.append(".yang"); + return filename.toString(); + } + +} \ No newline at end of file diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java index 575af04dbb..39c4c5e78a 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java @@ -50,8 +50,12 @@ public abstract class AbstractDataNodeContainerBuilder extends AbstractBuilder i return qname; } + public Map getChildNodes() { + return childNodes; + } + @Override - public Set getChildNodes() { + public Set getChildNodeBuilders() { return addedChildNodes; } @@ -121,7 +125,16 @@ public abstract class AbstractDataNodeContainerBuilder extends AbstractBuilder i } @Override - public Set getUsesNodes() { + public Set> getTypeDefinitions() { + return typedefs; + } + + public Set getUsesNodes() { + return usesNodes; + } + + @Override + public Set getUsesNodeBuilders() { return addedUsesNodes; } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataNodeContainerBuilder.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataNodeContainerBuilder.java index e2eac3fc1c..ecedd8ef48 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataNodeContainerBuilder.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataNodeContainerBuilder.java @@ -13,6 +13,7 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; /** * Interface for all yang data-node containers [augment, case, container, @@ -39,7 +40,7 @@ public interface DataNodeContainerBuilder extends Builder { * * @return collection child nodes builders */ - Set getChildNodes(); + Set getChildNodeBuilders(); /** * Get child node by name. @@ -87,7 +88,7 @@ public interface DataNodeContainerBuilder extends Builder { * * @return collection of uses builders */ - Set getUsesNodes(); + Set getUsesNodeBuilders(); /** * Add builder of uses statement to this node. @@ -96,6 +97,8 @@ public interface DataNodeContainerBuilder extends Builder { */ void addUsesNode(UsesNodeBuilder usesBuilder); + Set> getTypeDefinitions(); + /** * Get builders of typedef statement defined in this node. * diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java index f18b784666..e8ff3040eb 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java @@ -138,7 +138,7 @@ public final class GroupingBuilderImpl extends AbstractDataNodeContainerBuilder for (GroupingBuilder node : addedGroupings) { GroupingBuilder copy = CopyUtils.copy(node, newParent, true); copy.setAddedByUses(true); - for (DataSchemaNodeBuilder childNode : copy.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : copy.getChildNodeBuilders()) { ParserUtils.setNodeAddedByUses(childNode); } nodes.add(copy); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java index 13372b1c38..15969e6677 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java @@ -32,6 +32,18 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { private String prefix; private Date revision; + private final boolean submodule; + private String belongsTo; + private ModuleBuilder parent; + + public ModuleBuilder getParent() { + return parent; + } + + public void setParent(ModuleBuilder parent) { + this.parent = parent; + } + private final Deque actualPath = new LinkedList<>(); private final Set dirtyNodes = new HashSet<>(); @@ -66,10 +78,15 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { private final List allUnknownNodes = new ArrayList(); public ModuleBuilder(final String name) { + this(name, false); + } + + public ModuleBuilder(final String name, final boolean submodule) { super(name, 0, null); this.name = name; schemaPath = new SchemaPath(Collections. emptyList(), true); instance = new ModuleImpl(name); + this.submodule = submodule; actualPath.push(this); } @@ -78,6 +95,7 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { this.name = base.getName(); schemaPath = new SchemaPath(Collections. emptyList(), true); instance = new ModuleImpl(base.getName()); + submodule = false; actualPath.push(this); namespace = base.getNamespace(); @@ -235,14 +253,34 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { return dirtyNodes; } + public Set getAugments() { + return augments; + } + + public List getAugmentBuilders() { + return augmentBuilders; + } + public List getAllAugments() { return allAugments; } - public Set getIdentities() { + public Set getIdentities() { + return identities; + } + + public Set getAddedIdentities() { return addedIdentities; } + public Set getFeatures() { + return features; + } + + public Set getAddedFeatures() { + return addedFeatures; + } + public List getAllGroupings() { return allGroupings; } @@ -251,11 +289,19 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { return allUsesNodes; } - public Set getDeviations() { + public Set getDeviations() { + return deviations; + } + + public Set getDeviationBuilders() { return deviationBuilders; } - public List getExtensions() { + public List getExtensions() { + return extensions; + } + + public List getAddedExtensions() { return addedExtensions; } @@ -283,6 +329,18 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { return revision; } + public boolean isSubmodule() { + return submodule; + } + + public String getBelongsTo() { + return belongsTo; + } + + public void setBelongsTo(String belongsTo) { + this.belongsTo = belongsTo; + } + public void markActualNodeDirty() { final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) getActualNode(); dirtyNodes.add(nodeBuilder); @@ -794,11 +852,19 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { return builder; } - public Set getRpcs() { + public Set getRpcs() { + return rpcs; + } + + public Set getAddedRpcs() { return addedRpcs; } - public Set getNotifications() { + public Set getNotifications() { + return notifications; + } + + public Set getAddedNotifications() { return addedNotifications; } @@ -1232,7 +1298,7 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder { // defined only under module or submodule if (parent instanceof DataNodeContainerBuilder) { DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent; - for (DataSchemaNodeBuilder childNode : parentNode.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) { if (childNode.getQName().getLocalName().equals(childName)) { raiseYangParserException("'" + child + "'", "node", childName, lineNum, childNode.getLine()); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java index 54a4b62dd7..c63a52bd21 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java @@ -27,6 +27,7 @@ import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.*; import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; @@ -39,15 +40,7 @@ import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.*; import org.opendaylight.yangtools.yang.parser.util.GroupingSort; import org.opendaylight.yangtools.yang.parser.util.GroupingUtils; import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort; @@ -98,17 +91,18 @@ public final class YangParserImpl implements YangModelParser { } } - Map parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()), + Map parsedBuilders = parseBuilders(new ArrayList<>(streamToFileMap.keySet()), new HashMap()); ModuleBuilder main = parsedBuilders.get(yangFileStream); List moduleBuilders = new ArrayList<>(); moduleBuilders.add(main); filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders); + Collection result = resolveSubmodules(moduleBuilders); // module builders sorted by dependencies - ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()]; - moduleBuilders.toArray(builders); + ModuleBuilder[] builders = new ModuleBuilder[result.size()]; + result.toArray(builders); List sortedBuilders = ModuleDependencySort.sort(builders); LinkedHashMap> modules = orderModules(sortedBuilders); Collection unsorted = build(modules).values(); @@ -250,7 +244,13 @@ public final class YangParserImpl implements YangModelParser { private Map parseModuleBuilders(List inputStreams, Map streamToBuilderMap) { + Map modules = parseBuilders(inputStreams, streamToBuilderMap); + Map result = resolveSubmodules(modules); + return result; + } + private Map parseBuilders(List inputStreams, + Map streamToBuilderMap) { final ParseTreeWalker walker = new ParseTreeWalker(); final Map trees = parseStreams(inputStreams); final Map builders = new LinkedHashMap<>(); @@ -266,12 +266,90 @@ public final class YangParserImpl implements YangModelParser { // We expect the order of trees and streams has to be the same streamToBuilderMap.put(moduleBuilder, entry.getKey()); + builders.put(entry.getKey(), moduleBuilder); } return builders; } + private Map resolveSubmodules(Map builders) { + Map modules = new HashMap<>(); + Set submodules = new HashSet<>(); + for (Map.Entry entry : builders.entrySet()) { + ModuleBuilder moduleBuilder = entry.getValue(); + if (moduleBuilder.isSubmodule()) { + submodules.add(moduleBuilder); + } else { + modules.put(entry.getKey(), moduleBuilder); + } + } + + Collection values = modules.values(); + for (ModuleBuilder submodule : submodules) { + for (ModuleBuilder module : values) { + if (module.getName().equals(submodule.getBelongsTo())) { + addSubmoduleToModule(submodule, module); + } + } + } + return modules; + } + + private Collection resolveSubmodules(Collection builders) { + Collection modules = new HashSet<>(); + Set submodules = new HashSet<>(); + for (ModuleBuilder moduleBuilder : builders) { + if (moduleBuilder.isSubmodule()) { + submodules.add(moduleBuilder); + } else { + modules.add(moduleBuilder); + } + } + + for (ModuleBuilder submodule : submodules) { + for (ModuleBuilder module : modules) { + if (module.getName().equals(submodule.getBelongsTo())) { + addSubmoduleToModule(submodule, module); + } + } + } + return modules; + } + + private void addSubmoduleToModule(ModuleBuilder submodule, ModuleBuilder module) { + submodule.setParent(module); + module.getDirtyNodes().addAll(submodule.getDirtyNodes()); + module.getModuleImports().addAll(submodule.getModuleImports()); + module.getAugments().addAll(submodule.getAugments()); + module.getAugmentBuilders().addAll(submodule.getAugmentBuilders()); + module.getAllAugments().addAll(submodule.getAllAugments()); + module.getChildNodeBuilders().addAll(submodule.getChildNodeBuilders()); + module.getChildNodes().putAll(submodule.getChildNodes()); + module.getGroupings().addAll(submodule.getGroupings()); + module.getGroupingBuilders().addAll(submodule.getGroupingBuilders()); + module.getTypeDefinitions().addAll(submodule.getTypeDefinitions()); + module.getTypeDefinitionBuilders().addAll(submodule.getTypeDefinitionBuilders()); + module.getUsesNodes().addAll(submodule.getUsesNodes()); + module.getUsesNodeBuilders().addAll(submodule.getUsesNodeBuilders()); + module.getAllGroupings().addAll(submodule.getAllGroupings()); + module.getAllUsesNodes().addAll(submodule.getAllUsesNodes()); + module.getRpcs().addAll(submodule.getRpcs()); + module.getAddedRpcs().addAll(submodule.getAddedRpcs()); + module.getNotifications().addAll(submodule.getNotifications()); + module.getAddedNotifications().addAll(submodule.getAddedNotifications()); + module.getIdentities().addAll(submodule.getIdentities()); + module.getAddedIdentities().addAll(submodule.getAddedIdentities()); + module.getFeatures().addAll(submodule.getFeatures()); + module.getAddedFeatures().addAll(submodule.getAddedFeatures()); + module.getDeviations().addAll(submodule.getDeviations()); + module.getDeviationBuilders().addAll(submodule.getDeviationBuilders()); + module.getExtensions().addAll(submodule.getExtensions()); + module.getAddedExtensions().addAll(submodule.getAddedExtensions()); + module.getUnknownNodes().addAll(submodule.getUnknownNodes()); + module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes()); + } + private Map> resolveModuleBuilders(final List yangFileStreams, final Map streamToBuilderMap, final SchemaContext context) { Map parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap); @@ -317,7 +395,22 @@ public final class YangParserImpl implements YangModelParser { } private void filterImports(ModuleBuilder main, List other, List filtered) { - for (ModuleImport mi : main.getModuleImports()) { + Set imports = main.getModuleImports(); + + // if this is submodule, add parent to filtered and pick its imports + if (main.isSubmodule()) { + TreeMap dependencies = new TreeMap<>(); + for (ModuleBuilder mb : other) { + if (mb.getName().equals(main.getBelongsTo())) { + dependencies.put(mb.getRevision(), mb); + } + } + ModuleBuilder parent = dependencies.get(dependencies.firstKey()); + filtered.add(parent); + imports.addAll(parent.getModuleImports()); + } + + for (ModuleImport mi : imports) { for (ModuleBuilder builder : other) { if (mi.getModuleName().equals(builder.getModuleName())) { if (mi.getRevision() == null) { @@ -363,6 +456,21 @@ public final class YangParserImpl implements YangModelParser { } return result; } + + public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) { + YangContext result = null; + try { + final ANTLRInputStream input = new ANTLRInputStream(yangStream); + final YangLexer lexer = new YangLexer(input); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + final YangParser parser = new YangParser(tokens); + parser.removeErrorListeners(); + result = parser.yang(); + } catch (IOException e) { + LOG.warn("Exception while reading yang file: " + yangStream, e); + } + return result; + } private Map build(final Map> modules) { // fix unresolved nodes @@ -568,7 +676,7 @@ public final class YangParserImpl implements YangModelParser { } augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute())); - for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath()); } } @@ -577,7 +685,7 @@ public final class YangParserImpl implements YangModelParser { SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName()); node.setPath(newPath); if (node instanceof DataNodeContainerBuilder) { - for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodes()) { + for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) { correctPathForAugmentNodes(child, node.getPath()); } } @@ -606,7 +714,7 @@ public final class YangParserImpl implements YangModelParser { continue; } - for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { if (childNode.getConstraints().isMandatory()) { throw new YangParseException(augment.getModuleName(), augment.getLine(), "Error in augment parsing: cannot augment mandatory node " @@ -749,7 +857,7 @@ public final class YangParserImpl implements YangModelParser { * module being resolved */ private void resolveIdentities(final Map> modules, final ModuleBuilder module) { - final Set identities = module.getIdentities(); + final Set identities = module.getAddedIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { final String baseIdentityName = identity.getBaseIdentityName(); final int line = identity.getLine(); @@ -778,7 +886,7 @@ public final class YangParserImpl implements YangModelParser { */ private void resolveIdentitiesWithContext(final Map> modules, final ModuleBuilder module, final SchemaContext context) { - final Set identities = module.getIdentities(); + final Set identities = module.getAddedIdentities(); for (IdentitySchemaNodeBuilder identity : identities) { final String baseIdentityName = identity.getBaseIdentityName(); final int line = identity.getLine(); @@ -875,7 +983,7 @@ public final class YangParserImpl implements YangModelParser { resolveUsesAugment(augment, module, modules, context); } } else { - parent.getChildNodes().addAll(target.instantiateChildNodes(parent)); + parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent)); parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent)); parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent)); parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); @@ -916,7 +1024,7 @@ public final class YangParserImpl implements YangModelParser { Set childNodes = wrapChildNodes(module.getModuleName(), line, gd.getChildNodes(), parentPath, ns, rev, pref); - parent.getChildNodes().addAll(childNodes); + parent.getChildNodeBuilders().addAll(childNodes); for (DataSchemaNodeBuilder childNode : childNodes) { setNodeAddedByUses(childNode); } @@ -949,7 +1057,7 @@ public final class YangParserImpl implements YangModelParser { try { ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(), usnb.getLine()); - for (ExtensionBuilder extension : dependentModule.getExtensions()) { + for (ExtensionBuilder extension : dependentModule.getAddedExtensions()) { if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { usnb.setNodeType(extension.getQName()); usnb.setExtensionBuilder(extension); @@ -983,7 +1091,7 @@ public final class YangParserImpl implements YangModelParser { } } } else { - for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) { + for (ExtensionBuilder extension : dependentModuleBuilder.getAddedExtensions()) { if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) { usnb.setExtensionBuilder(extension); break; @@ -1023,7 +1131,7 @@ public final class YangParserImpl implements YangModelParser { * module in which resolve deviations */ private void resolveDeviation(final Map> modules, final ModuleBuilder module) { - for (DeviationBuilder dev : module.getDeviations()) { + for (DeviationBuilder dev : module.getDeviationBuilders()) { int line = dev.getLine(); SchemaPath targetPath = dev.getTargetPath(); List path = targetPath.getPath(); @@ -1070,7 +1178,7 @@ public final class YangParserImpl implements YangModelParser { */ private void resolveDeviationWithContext(final Map> modules, final ModuleBuilder module, final SchemaContext context) { - for (DeviationBuilder dev : module.getDeviations()) { + for (DeviationBuilder dev : module.getDeviationBuilders()) { int line = dev.getLine(); SchemaPath targetPath = dev.getTargetPath(); List path = targetPath.getPath(); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java index f59f6881ae..12c230d5bc 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java @@ -110,6 +110,41 @@ public final class YangParserListenerImpl extends YangParserBaseListener { actualPath.pop(); } + @Override public void enterSubmodule_stmt(YangParser.Submodule_stmtContext ctx) { + moduleName = stringFromNode(ctx); + LOGGER.debug("entering submodule " + moduleName); + enterLog("submodule", moduleName, 0); + actualPath.push(new Stack()); + + moduleBuilder = new ModuleBuilder(moduleName, true); + + String description = null; + String reference = null; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } else { + if (description != null && reference != null) { + break; + } + } + } + moduleBuilder.setDescription(description); + moduleBuilder.setReference(reference); + } + + @Override public void exitSubmodule_stmt(YangParser.Submodule_stmtContext ctx) { + exitLog("submodule", ""); + actualPath.pop(); + } + + @Override public void enterBelongs_to_stmt(YangParser.Belongs_to_stmtContext ctx) { + moduleBuilder.setBelongsTo(stringFromNode(ctx)); + } + @Override public void enterModule_header_stmts(Module_header_stmtsContext ctx) { enterLog("module_header", "", ctx.getStart().getLine()); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java new file mode 100644 index 0000000000..741d4df868 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java @@ -0,0 +1,274 @@ +package org.opendaylight.yangtools.yang.parser.impl.util; + +import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getArgumentString; +import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getFirstContext; + +import java.io.InputStream; +import java.util.Date; +import java.util.List; + +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext; +import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; + +public abstract class YangModelDependencyInfo { + + private final String name; + private final String formattedRevision; + private final Date revision; + private final ImmutableSet submoduleIncludes; + private final ImmutableSet moduleImports; + private final ImmutableSet dependencies; + + public YangModelDependencyInfo(String name, String formattedRevision, ImmutableSet imports, + ImmutableSet includes) { + this.name = name; + this.formattedRevision = formattedRevision; + this.revision = QName.parseRevision(formattedRevision); + this.moduleImports = imports; + this.submoduleIncludes = includes; + this.dependencies = ImmutableSet. builder() // + .addAll(moduleImports) // + .addAll(submoduleIncludes) // + .build(); + } + + public ImmutableSet getDependencies() { + return dependencies; + } + + public String getName() { + return name; + } + + public String getFormattedRevision() { + return formattedRevision; + } + + public Date getRevision() { + return revision; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof YangModelDependencyInfo)) + return false; + YangModelDependencyInfo other = (YangModelDependencyInfo) obj; + if (formattedRevision == null) { + if (other.formattedRevision != null) + return false; + } else if (!formattedRevision.equals(other.formattedRevision)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + public static YangModelDependencyInfo fromInputStream(InputStream yangStream) { + YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream); + + Optional moduleCtx = getFirstContext(yangContext, Module_stmtContext.class); + if (moduleCtx.isPresent()) { + return fromModuleContext(moduleCtx.get()); + } + Optional submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class); + if (submoduleCtx.isPresent()) { + return fromSubmoduleContext(submoduleCtx.get()); + } + throw new IllegalArgumentException("Supplied stream is not valid yang file."); + } + + private static YangModelDependencyInfo fromModuleContext(Module_stmtContext module) { + String name = getArgumentString(module); + // String prefix = + // getArgumentString(module.module_header_stmts().prefix_stmt(0)); + String namespace = getArgumentString(module.module_header_stmts().namespace_stmt(0)); + String latestRevision = getLatestRevision(module.revision_stmts()); + ImmutableSet imports = getImports(module.linkage_stmts().import_stmt()); + ImmutableSet includes = getIncludes(module.linkage_stmts().include_stmt()); + + return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes); + } + + private static ImmutableSet getImports(List importStatements) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (Import_stmtContext importStmt : importStatements) { + String moduleName = getArgumentString(importStmt); + Date revision = getRevision(importStmt.revision_date_stmt()); + String prefix = getArgumentString(importStmt.prefix_stmt()); + builder.add(new ModuleImportImpl(moduleName, revision)); + } + return builder.build(); + } + + private static String getLatestRevision(Revision_stmtsContext revision_stmts) { + List revisions = revision_stmts.getRuleContexts(Revision_stmtContext.class); + String latestRevision = null; + for (Revision_stmtContext revisionStmt : revisions) { + String currentRevision = getArgumentString(revisionStmt); + if (latestRevision == null || latestRevision.compareTo(currentRevision) == 1) { + latestRevision = currentRevision; + } + } + return latestRevision; + } + + private static YangModelDependencyInfo fromSubmoduleContext(Submodule_stmtContext submodule) { + String name = getArgumentString(submodule); + Belongs_to_stmtContext belongsToStmt = submodule.submodule_header_stmts().belongs_to_stmt(0); + String belongsTo = getArgumentString(belongsToStmt); + + String latestRevision = getLatestRevision(submodule.revision_stmts()); + ImmutableSet imports = getImports(submodule.linkage_stmts().import_stmt()); + ImmutableSet includes = getIncludes(submodule.linkage_stmts().include_stmt()); + + return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes); + } + + private static ImmutableSet getIncludes(List importStatements) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (Include_stmtContext importStmt : importStatements) { + String moduleName = getArgumentString(importStmt); + Date revision = getRevision(importStmt.revision_date_stmt()); + builder.add(new ModuleImportImpl(moduleName, revision)); + } + return builder.build(); + } + + private static Date getRevision(Revision_date_stmtContext revision_date_stmt) { + if (revision_date_stmt == null) { + return null; + } + String formatedDate = getArgumentString(revision_date_stmt); + return QName.parseRevision(formatedDate); + } + + public static final class ModuleDependencyInfo extends YangModelDependencyInfo { + + private ModuleDependencyInfo(String name, String latestRevision, String namespace, + ImmutableSet imports, ImmutableSet includes) { + super(name, latestRevision, imports, includes); + } + + @Override + public String toString() { + return "Module [name=" + getName() + ", revision=" + getRevision() + + ", dependencies=" + getDependencies() + "]"; + } + + } + + public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo { + + private final String belongsTo; + + public String getParentModule() { + return belongsTo; + } + + private SubmoduleDependencyInfo(String name, String latestRevision, String belongsTo, + ImmutableSet imports, ImmutableSet includes) { + super(name, latestRevision, imports, includes); + this.belongsTo = belongsTo; + } + + @Override + public String toString() { + return "Submodule [name=" + getName() + ", revision=" + getRevision() + + ", dependencies=" + getDependencies() + "]"; + } + + } + + private static final class ModuleImportImpl implements ModuleImport { + + private Date revision; + private String name; + + public ModuleImportImpl(String moduleName, Date revision) { + this.name = moduleName; + this.revision = revision; + } + + @Override + public String getModuleName() { + return this.name; + } + + @Override + public Date getRevision() { + return this.revision; + } + + @Override + public String getPrefix() { + return null; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((revision == null) ? 0 : revision.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ModuleImportImpl other = (ModuleImportImpl) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (revision == null) { + if (other.revision != null) + return false; + } else if (!revision.equals(other.revision)) + return false; + return true; + } + + @Override + public String toString() { + return "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]"; + } + + + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java new file mode 100644 index 0000000000..fb784d1178 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java @@ -0,0 +1,254 @@ +package org.opendaylight.yangtools.yang.parser.impl.util; + +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider; +import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet.Builder; + +public class YangSourceContext implements SchemaSourceProvider,AutoCloseable { + + private final ImmutableSet validSources; + + + private final ImmutableSet missingSources; + private final ImmutableMultimap missingDependencies; + private SchemaSourceProvider sourceProvider; + + private YangSourceContext(ImmutableSet validSourcesSet, + ImmutableSet missingSourcesSet, + ImmutableMultimap missingDependenciesMap, SchemaSourceProvider sourceProvicer) { + validSources = validSourcesSet; + missingSources = missingSourcesSet; + missingDependencies = missingDependenciesMap; + sourceProvider = sourceProvicer; + } + + public ImmutableSet getValidSources() { + return validSources; + } + + public ImmutableSet getMissingSources() { + return missingSources; + } + + public ImmutableMultimap getMissingDependencies() { + return missingDependencies; + } + + @Override + public Optional getSchemaSource(String moduleName, Optional revision) { + return getSchemaSource(SourceIdentifier.create(moduleName,revision)); + } + + @Override + public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + if(validSources.contains(sourceIdentifier)) { + return getDelegateChecked().getSchemaSource(sourceIdentifier); + } + return Optional.absent(); + } + + private SchemaSourceProvider getDelegateChecked() { + Preconditions.checkState(sourceProvider != null,"Instance is already closed."); + return sourceProvider; + } + + @Override + public void close() { + if(sourceProvider != null) { + sourceProvider = null; + } + } + + public static final YangSourceContext createFrom(Iterable capabilities, + SchemaSourceProvider schemaSourceProvider) { + YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider); + return resolver.resolveContext(); + } + + public static final SchemaContext toSchemaContext(YangSourceContext context) { + List inputStreams = getValidInputStreams(context); + YangParserImpl parser = new YangParserImpl(); + Set models = parser.parseYangModelsFromStreams(inputStreams); + return parser.resolveSchemaContext(models); + } + + public static List getValidInputStreams(YangSourceContext context) { + return getValidInputStreams(context, context.sourceProvider); + } + + public static List getValidInputStreams(YangSourceContext context, SchemaSourceProvider provider) { + // TODO Auto-generated method stub + final HashSet sourcesToLoad = new HashSet<>(); + sourcesToLoad.addAll(context.getValidSources()); + for(SourceIdentifier source : context.getValidSources()) { + if(source.getRevision() != null) { + SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(), Optional.absent()); + sourcesToLoad.removeAll(Collections.singleton(sourceWithoutRevision)); + } + } + + ImmutableList.Builder ret = ImmutableList.builder(); + for(SourceIdentifier sourceIdentifier : sourcesToLoad) { + Optional source = provider.getSchemaSource(sourceIdentifier); + ret.add(source.get()); + } + return ret.build(); + } + + + public static abstract class YangSourceContextResolver { + + private static final Logger LOG = LoggerFactory.getLogger(YangSourceContextResolver.class); + + private SchemaSourceProvider sourceProvicer; + + private HashMap alreadyProcessed = new HashMap<>(); + + private ImmutableSet.Builder missingSources = ImmutableSet.builder(); + + private ImmutableMultimap.Builder missingDependencies = ImmutableMultimap + .builder(); + + private ImmutableSet.Builder validSources = ImmutableSet.builder(); + + public YangSourceContextResolver(SchemaSourceProvider schemaSourceProvider) { + sourceProvicer = schemaSourceProvider; + } + + public abstract YangSourceContext resolveContext(); + + public ResolutionState resolveSource(String name, Optional formattedRevision) { + return resolveSource(new SourceIdentifier(name, formattedRevision)); + } + + private ResolutionState resolveSource(SourceIdentifier identifier) { + + if (alreadyProcessed.containsKey(identifier)) { + return alreadyProcessed.get(identifier); + } + LOG.info("Resolving source: {}",identifier); + ResolutionState potentialState = ResolutionState.EVERYTHING_OK; + try { + Optional source = getSchemaSource(identifier); + if (source.isPresent()) { + + YangModelDependencyInfo info = YangModelDependencyInfo.fromInputStream(source.get()); + + checkValidSource(identifier,info); + + for (ModuleImport dependency : info.getDependencies()) { + LOG.debug("Source: {} Resolving dependency: {}",identifier,dependency); + ResolutionState dependencyState = resolveDependency(dependency); + if (dependencyState == ResolutionState.MISSING_SOURCE) { + potentialState = ResolutionState.MISSING_DEPENDENCY; + missingDependencies.put(identifier, dependency); + } + } + } else { + missingSources.add(identifier); + return ResolutionState.MISSING_SOURCE; + } + } catch (Exception e) { + potentialState = ResolutionState.OTHER_ERROR; + } + updateResolutionState(identifier, potentialState); + return potentialState; + } + + private boolean checkValidSource(SourceIdentifier identifier, YangModelDependencyInfo info) { + if(!identifier.getName().equals(info.getName())) { + LOG.warn("Incorrect model returned. Identifier name was: {}, source contained: {}", identifier.getName(),info.getName()); + throw new IllegalStateException("Incorrect source was returned"); + } + return true; + } + + private void updateResolutionState(SourceIdentifier identifier, ResolutionState potentialState) { + alreadyProcessed.put(identifier, potentialState); + switch (potentialState) { + case MISSING_SOURCE: + missingSources.add(identifier); + break; + case EVERYTHING_OK: + validSources.add(identifier); + break; + default: + break; + } + } + + private ResolutionState resolveDependency(ModuleImport dependency) { + String name = dependency.getModuleName(); + Optional formattedRevision = Optional + .fromNullable(QName.formattedRevision(dependency.getRevision())); + return resolveSource(new SourceIdentifier(name, formattedRevision)); + } + + private Optional getSchemaSource(SourceIdentifier identifier) { + return sourceProvicer + .getSchemaSource(identifier.getName(), Optional.fromNullable(identifier.getRevision())); + } + + protected YangSourceContext createSourceContext() { + + ImmutableSet missingSourcesSet = missingSources.build(); + ImmutableMultimap missingDependenciesMap = missingDependencies.build(); + ImmutableSet validSourcesSet = validSources.build(); + + + return new YangSourceContext(validSourcesSet,missingSourcesSet,missingDependenciesMap,sourceProvicer); + + } + } + + private enum ResolutionState { + MISSING_SOURCE, MISSING_DEPENDENCY, OTHER_ERROR, EVERYTHING_OK + } + + public static final class YangSourceFromCapabilitiesResolver extends YangSourceContextResolver { + + private Iterable capabilities; + + public YangSourceFromCapabilitiesResolver(Iterable capabilities, + SchemaSourceProvider schemaSourceProvider) { + super(schemaSourceProvider); + this.capabilities = capabilities; + } + + @Override + public YangSourceContext resolveContext() { + for (QName capability : capabilities) { + resolveCapability(capability); + } + return createSourceContext(); + } + + private void resolveCapability(QName capability) { + super.resolveSource(capability.getLocalName(), Optional.fromNullable(capability.getFormattedRevision())); + } + } + + +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/CopyUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/CopyUtils.java index 153ac29b18..3cee12eb10 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/CopyUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/CopyUtils.java @@ -122,7 +122,7 @@ public final class CopyUtils { copy.setReference(old.getReference()); copy.setStatus(old.getStatus()); copy.setAugmenting(old.isAugmenting()); - for (DataSchemaNodeBuilder childNode : old.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) { copy.addChildNode(copy(childNode, copy, updateQName)); } copy.getGroupings().addAll(old.getGroupings()); @@ -132,7 +132,7 @@ public final class CopyUtils { for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) { copy.addTypedef(copy(tdb, copy, updateQName)); } - for (UsesNodeBuilder oldUses : old.getUsesNodes()) { + for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) { copy.addUsesNode(copyUses(oldUses, copy)); } for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) { @@ -159,7 +159,7 @@ public final class CopyUtils { copy.setAugmenting(old.isAugmenting()); copy.setAddedByUses(old.isAddedByUses()); copy.setConfiguration(old.isConfiguration()); - for (DataSchemaNodeBuilder childNode : old.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) { copy.addChildNode(copy(childNode, copy, updateQName)); } copy.getGroupings().addAll(old.getGroupings()); @@ -169,7 +169,7 @@ public final class CopyUtils { for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) { copy.addTypedef(copy(tdb, copy, updateQName)); } - for (UsesNodeBuilder oldUses : old.getUsesNodes()) { + for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) { copy.addUsesNode(copyUses(oldUses, copy)); } for (AugmentationSchemaBuilder augment : old.getAugmentationBuilders()) { @@ -258,7 +258,7 @@ public final class CopyUtils { copy.setAugmenting(old.isAugmenting()); copy.setAddedByUses(old.isAddedByUses()); copy.setConfiguration(old.isConfiguration()); - for (DataSchemaNodeBuilder childNode : old.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) { copy.addChildNode(copy(childNode, copy, updateQName)); } copy.getGroupings().addAll(old.getGroupings()); @@ -268,7 +268,7 @@ public final class CopyUtils { for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) { copy.addTypedef(copy(tdb, copy, updateQName)); } - for (UsesNodeBuilder oldUses : old.getUsesNodes()) { + for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) { copy.addUsesNode(copyUses(oldUses, copy)); } for (AugmentationSchemaBuilder augment : old.getAugmentationBuilders()) { @@ -295,7 +295,7 @@ public final class CopyUtils { copy.setReference(old.getReference()); copy.setStatus(old.getStatus()); copy.setAddedByUses(old.isAddedByUses()); - for (DataSchemaNodeBuilder childNode : old.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) { copy.addChildNode(copy(childNode, copy, updateQName)); } copy.getGroupings().addAll(old.getGroupings()); @@ -305,7 +305,7 @@ public final class CopyUtils { for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) { copy.addTypedef(copy(tdb, copy, updateQName)); } - for (UsesNodeBuilder oldUses : old.getUsesNodes()) { + for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) { copy.addUsesNode(copyUses(oldUses, copy)); } for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) { @@ -397,10 +397,10 @@ public final class CopyUtils { copy.setStatus(old.getStatus()); copy.addWhenCondition(old.getWhenCondition()); copy.setTargetNodeSchemaPath(old.getTargetNodeSchemaPath()); - for (DataSchemaNodeBuilder childNode : old.getChildNodes()) { + for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) { copy.addChildNode(copy(childNode, copy, false)); } - for (UsesNodeBuilder oldUses : old.getUsesNodes()) { + for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) { copy.addUsesNode(copyUses(oldUses, copy)); } for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingSort.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingSort.java index 86a062f753..580c6deca1 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingSort.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingSort.java @@ -122,7 +122,7 @@ public class GroupingSort { */ public static Set getAllUsesNodes(DataNodeContainerBuilder container) { Set ret = new HashSet<>(); - Set usesNodes = container.getUsesNodes(); + Set usesNodes = container.getUsesNodeBuilders(); ret.addAll(usesNodes); for (UsesNodeBuilder usesNode : usesNodes) { @@ -134,7 +134,7 @@ public class GroupingSort { for (GroupingBuilder groupingDefinition : groupings) { ret.addAll(getAllUsesNodes(groupingDefinition)); } - Set childNodes = container.getChildNodes(); + Set childNodes = container.getChildNodeBuilders(); for (DataSchemaNodeBuilder childNode : childNodes) { if (childNode instanceof DataNodeContainerBuilder) { ret.addAll(getAllUsesNodes((DataNodeContainerBuilder) childNode)); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingUtils.java index d3e44832fb..2b37a2ce70 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingUtils.java @@ -62,6 +62,9 @@ public final class GroupingUtils { } ModuleBuilder dependentModule; + if(groupingPrefix == null) { + dependentModule = module; + } if (groupingPrefix.equals(module.getPrefix())) { dependentModule = module; } else { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java index ff96d95d82..3b3423030c 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java @@ -7,6 +7,8 @@ */ package org.opendaylight.yangtools.yang.parser.util; +import static com.google.common.base.Preconditions.checkState; + import java.math.BigDecimal; import java.net.URI; import java.util.ArrayList; @@ -15,8 +17,10 @@ import java.util.Date; import java.util.List; import java.util.Stack; +import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; +import org.omg.CORBA.CTX_RESTRICT_SCOPE; import org.opendaylight.yangtools.antlrv4.code.gen.*; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext; @@ -121,6 +125,8 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + public final class ParserListenerUtils { private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class); @@ -140,7 +146,7 @@ public final class ParserListenerUtils { if (treeNode.getChild(i) instanceof StringContext) { final StringContext context = (StringContext) treeNode.getChild(i); if (context != null) { - return stringFromStringContext(context,treeNode); + return stringFromStringContext(context); } } @@ -148,14 +154,14 @@ public final class ParserListenerUtils { return result; } - private static String stringFromStringContext(StringContext context, ParseTree treeNode) { + public static String stringFromStringContext(StringContext context) { StringBuilder str = new StringBuilder(); for (TerminalNode stringNode : context.STRING()) { String result = stringNode.getText(); if(!result.contains("\"")){ str.append(result); } else if (!(result.startsWith("\"")) && result.endsWith("\"")) { - LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(treeNode), + LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(context), context.getStart().getLine()); } else { str.append(result.replace("\"", "")); @@ -1671,4 +1677,18 @@ public final class ParserListenerUtils { return refine; } + public static String getArgumentString(org.antlr.v4.runtime.ParserRuleContext ctx) { + List potentialValues = ctx.getRuleContexts(StringContext.class); + checkState(!potentialValues.isEmpty()); + return ParserListenerUtils.stringFromStringContext(potentialValues.get(0)); + } + + public static Optional getFirstContext(ParserRuleContext context,Class contextType) { + List potential = context.getRuleContexts(contextType); + if(potential.isEmpty()) { + return Optional.absent(); + } + return Optional.of(potential.get(0)); + } + } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserUtils.xtend b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserUtils.xtend index 16b740b77b..861778590e 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserUtils.xtend +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserUtils.xtend @@ -59,6 +59,7 @@ import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode import org.opendaylight.yangtools.yang.model.api.DataNodeContainer +import com.google.common.base.Preconditions public final class ParserUtils { @@ -115,7 +116,9 @@ public final class ParserUtils { var ModuleBuilder dependentModule = null; var Date dependentModuleRevision = null; - if (prefix.equals(module.getPrefix())) { + if(prefix == null) { + dependentModule = module; + } else if (prefix.equals(module.getPrefix())) { dependentModule = module; } else { val ModuleImport dependentModuleImport = getModuleImport(module, prefix); @@ -223,7 +226,7 @@ public final class ParserUtils { * augmentation target node */ public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, DataNodeContainerBuilder target) { - for (DataSchemaNodeBuilder child : augment.getChildNodes()) { + for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) { val childCopy = CopyUtils.copy(child, target, false); if (augment.parent instanceof UsesNodeBuilder) { setNodeAddedByUses(childCopy); @@ -249,7 +252,7 @@ public final class ParserUtils { * augmentation target choice node */ public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, ChoiceBuilder target) { - for (DataSchemaNodeBuilder builder : augment.getChildNodes()) { + for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) { val childCopy = CopyUtils.copy(builder, target, false); if (augment.parent instanceof UsesNodeBuilder) { setNodeAddedByUses(childCopy); @@ -257,7 +260,7 @@ public final class ParserUtils { setNodeAugmenting(childCopy) target.addCase(childCopy); } - for (UsesNodeBuilder usesNode : augment.getUsesNodes()) { + for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) { if (usesNode !== null) { throw new YangParseException(augment.getModuleName(), augment.getLine(), "Error in augment parsing: cannot augment choice with nodes from grouping"); @@ -272,7 +275,7 @@ public final class ParserUtils { child.setAugmenting(true); if (child instanceof DataNodeContainerBuilder) { val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder; - for (inner : dataNodeChild.getChildNodes()) { + for (inner : dataNodeChild.getChildNodeBuilders()) { setNodeAugmenting(inner); } } else if (child instanceof ChoiceBuilder) { @@ -290,7 +293,7 @@ public final class ParserUtils { child.setAddedByUses(true); if (child instanceof DataNodeContainerBuilder) { val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder; - for (inner : dataNodeChild.getChildNodes()) { + for (inner : dataNodeChild.getChildNodeBuilders()) { setNodeAddedByUses(inner); } } else if (child instanceof ChoiceBuilder) { @@ -338,7 +341,7 @@ public final class ParserUtils { var SchemaNodeBuilder node = module.getDataChildByName(first.localName) if (node == null) { - val notifications = module.notifications + val notifications = module.getAddedNotifications for (notification : notifications) { if (notification.QName.localName.equals(first.localName)) { node = notification @@ -346,7 +349,7 @@ public final class ParserUtils { } } if (node == null) { - val rpcs = module.rpcs + val rpcs = module.getAddedRpcs for (rpc : rpcs) { if (rpc.QName.localName.equals(first.localName)) { node = rpc @@ -408,10 +411,10 @@ public final class ParserUtils { val name = splittedBase.get(1); val dependentModule = findModuleFromBuilders(modules, module, prefix, line); if (dependentModule !== null) { - result = findIdentity(dependentModule.identities, name); + result = findIdentity(dependentModule.getAddedIdentities, name); } } else { - result = findIdentity(module.identities, baseString); + result = findIdentity(module.getAddedIdentities, baseString); } return result; } @@ -467,7 +470,12 @@ public final class ParserUtils { while (!(parent instanceof ModuleBuilder)) { parent = parent.getParent(); } - return parent as ModuleBuilder; + Preconditions.checkState(parent instanceof ModuleBuilder) + var parentModule = parent as ModuleBuilder + if(parentModule.submodule) { + parentModule = parentModule.parent; + } + return parentModule; } public static def Set wrapChildNodes(String moduleName, int line, Set nodes, diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserTest.java index bb2fea413b..e29cc9a07e 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserTest.java @@ -44,6 +44,8 @@ import org.opendaylight.yangtools.yang.model.util.Uint32; import org.opendaylight.yangtools.yang.model.util.UnionType; public class YangParserTest { + public static final String FS = File.separator; + private final URI fooNS = URI.create("urn:opendaylight.foo"); private final URI barNS = URI.create("urn:opendaylight.bar"); private final URI bazNS = URI.create("urn:opendaylight.baz"); @@ -910,4 +912,28 @@ public class YangParserTest { } } + @Test + public void testSubmodules() { + String yangFilePath = getClass().getResource(FS + "submodule-test" + FS + "subfoo.yang").getPath(); + String directoryPath = getClass().getResource(FS + "model").getPath(); + + File directory = new File(directoryPath); + File yangFile = new File(yangFilePath); + + Set modules = new YangParserImpl().parseYangModels(yangFile, directory); + assertEquals(3, modules.size()); + + Module foo = TestUtils.findModule(modules, "foo"); + + DataSchemaNode id = foo.getDataChildByName("id"); + assertNotNull(id); + DataSchemaNode subExt = foo.getDataChildByName("sub-ext"); + assertNotNull(subExt); + DataSchemaNode subTransfer = foo.getDataChildByName("sub-transfer"); + assertNotNull(subTransfer); + + assertEquals(2, foo.getExtensionSchemaNodes().size()); + assertEquals(2, foo.getAugmentations().size()); + } + } diff --git a/yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang b/yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang new file mode 100644 index 0000000000..1fe00c0bbf --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang @@ -0,0 +1,67 @@ +submodule subfoo { + yang-version 1; + + belongs-to foo { + prefix f; + } + + import bar { + prefix "br"; + revision-date 2013-07-03; + } + + import baz { + prefix "bz"; + revision-date 2013-02-27; + } + + revision "2013-02-27" { + } + + leaf id { + type br:int32-ext2 { + range "12..max"; + } + } + + container sub-ext { + bz:c-define "MY_INTERFACES"; + } + + + container sub-transfer { + choice how { + default interval; + container input { + } + list output { + leaf id { + type string; + } + } + case manual { + leaf manual { + type empty; + } + } + } + } + + anyxml sub-datas { + status obsolete; + } + + augment "/br:interfaces/br:ifEntry/bz:augment-holder" { + when "if:ifType='ds0'"; + leaf subleaf { + type string; + } + } + + extension sub-mountpoint { + argument "name" { + yin-element "true"; + } + } + +} -- 2.36.6