X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fimpl%2Futil%2FYangModelDependencyInfo.java;h=6b1abbc91158fe1089f5681c6c2a00e166a4196d;hb=b212baa59f859732bd3a799425bb420035fe6154;hp=6530c92510c8d6aabd43eb5640a4ae146b5c71ca;hpb=72d620c6fb5312f594474a992ec65154c2562b07;p=yangtools.git
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
index 6530c92510..6b1abbc911 100644
--- 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
@@ -3,77 +3,143 @@
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/eplv10.html
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
*/
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 static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
-import com.google.common.base.Optional;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
-
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
+import org.opendaylight.yangtools.concepts.SemVer;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.parser.rfc6020.repo.YangStatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.SupportedExtensionsMapping;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
+
+/**
+ * Helper transfer object which holds basic and dependency information for YANG
+ * model.
+ *
+ *
+ * There are two concrete implementations of this interface:
+ *
+ * - {@link ModuleDependencyInfo} - Dependency information for module
+ * - {@link SubmoduleDependencyInfo} - Dependency information for submodule
+ *
+ *
+ * @see ModuleDependencyInfo
+ * @see SubmoduleDependencyInfo
+ */
public abstract class YangModelDependencyInfo {
+ private static final String BELONGS_TO = YangStmtMapping.BELONGS_TO.getStatementName().getLocalName();
+ private static final String IMPORT = YangStmtMapping.IMPORT.getStatementName().getLocalName();
+ private static final String INCLUDE = YangStmtMapping.INCLUDE.getStatementName().getLocalName();
+ private static final String MODULE = YangStmtMapping.MODULE.getStatementName().getLocalName();
+ private static final String REVISION = YangStmtMapping.REVISION.getStatementName().getLocalName();
+ private static final String REVISION_DATE = YangStmtMapping.REVISION_DATE.getStatementName().getLocalName();
+ private static final String SUBMODULE = YangStmtMapping.SUBMODULE.getStatementName().getLocalName();
+
+ private static final String OPENCONFIG_VERSION = SupportedExtensionsMapping.OPENCONFIG_VERSION.getStatementName()
+ .getLocalName();
private final String name;
private final String formattedRevision;
- private final Date revision;
+ private final Revision revision;
+ private final Optional semVer;
private final ImmutableSet submoduleIncludes;
private final ImmutableSet moduleImports;
private final ImmutableSet dependencies;
- public YangModelDependencyInfo(final String name, final String formattedRevision, final ImmutableSet imports,
+ YangModelDependencyInfo(final String name, final String formattedRevision,
+ final ImmutableSet imports,
final ImmutableSet includes) {
+ this(name, formattedRevision, imports, includes, Optional.empty());
+ }
+
+ YangModelDependencyInfo(final String name, final String formattedRevision,
+ final ImmutableSet imports,
+ final ImmutableSet includes,
+ final Optional semVer) {
this.name = name;
this.formattedRevision = formattedRevision;
- this.revision = QName.parseRevision(formattedRevision);
+ this.revision = formattedRevision == null ? null : Revision.valueOf(formattedRevision);
this.moduleImports = imports;
this.submoduleIncludes = includes;
- this.dependencies = ImmutableSet. builder() //
- .addAll(moduleImports) //
- .addAll(submoduleIncludes) //
- .build();
+ this.dependencies = ImmutableSet.builder()
+ .addAll(moduleImports).addAll(submoduleIncludes).build();
+ this.semVer = semVer;
}
+ /**
+ * Returns immutable collection of all module imports. This collection contains both import
statements
+ * and include
statements for submodules.
+ *
+ * @return Immutable collection of imports.
+ */
public ImmutableSet getDependencies() {
return dependencies;
}
+ /**
+ * Returns model name.
+ *
+ * @return model name
+ */
public String getName() {
return name;
}
+ /**
+ * Returns formatted revision string.
+ *
+ * @return formatted revision string
+ */
public String getFormattedRevision() {
return formattedRevision;
}
- public Date getRevision() {
+ /**
+ * Returns revision.
+ *
+ * @return revision
+ */
+ Revision getRevision() {
return revision;
}
+ /**
+ * Returns semantic version of module.
+ *
+ * @return semantic version
+ */
+ public Optional getSemanticVersion() {
+ return semVer;
+ }
+
@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());
+ result = prime * result + Objects.hashCode(formattedRevision);
+ result = prime * result + Objects.hashCode(name);
+ result = prime * result + Objects.hashCode(semVer);
return result;
}
@@ -88,7 +154,7 @@ public abstract class YangModelDependencyInfo {
if (!(obj instanceof YangModelDependencyInfo)) {
return false;
}
- YangModelDependencyInfo other = (YangModelDependencyInfo) obj;
+ final YangModelDependencyInfo other = (YangModelDependencyInfo) obj;
if (formattedRevision == null) {
if (other.formattedRevision != null) {
return false;
@@ -103,140 +169,249 @@ public abstract class YangModelDependencyInfo {
} else if (!name.equals(other.name)) {
return false;
}
- return true;
+ return Objects.equals(semVer, other.semVer);
}
- public static YangModelDependencyInfo fromInputStream(final InputStream yangStream) {
- YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream);
+ /**
+ * Extracts {@link YangModelDependencyInfo} from an abstract syntax tree of a YANG model.
+ *
+ * @param tree Abstract syntax tree
+ * @return {@link YangModelDependencyInfo}
+ * @throws YangSyntaxErrorException If the AST is not a valid YANG module/submodule
+ */
+ public static YangModelDependencyInfo fromAST(final String name,
+ final ParserRuleContext tree) throws YangSyntaxErrorException {
+
+ if (tree instanceof StatementContext) {
+ final StatementContext rootStatement = (StatementContext) tree;
+ return parseAST(rootStatement, name);
+ }
+
+ throw new YangSyntaxErrorException(name, 0, 0, "Unknown YANG text type");
+ }
- Optional moduleCtx = getFirstContext(yangContext, Module_stmtContext.class);
- if (moduleCtx.isPresent()) {
- return fromModuleContext(moduleCtx.get());
+ private static YangModelDependencyInfo parseAST(final StatementContext rootStatement, final String sourceName) {
+ final String keyWordText = rootStatement.keyword().getText();
+ if (MODULE.equals(keyWordText)) {
+ return parseModuleContext(rootStatement, sourceName);
}
- Optional submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class);
- if (submoduleCtx.isPresent()) {
- return fromSubmoduleContext(submoduleCtx.get());
+ if (SUBMODULE.equals(keyWordText)) {
+ return parseSubmoduleContext(rootStatement, sourceName);
+ }
+ throw new IllegalArgumentException("Root of parsed AST must be either module or submodule");
+ }
+
+ /**
+ * Extracts {@link YangModelDependencyInfo} from input stream containing a YANG model. This parsing does not
+ * validate full YANG module, only parses header up to the revisions and imports.
+ *
+ * @param refClass Base search class
+ * @param resourceName resource name, relative to refClass
+ * @return {@link YangModelDependencyInfo}
+ * @throws YangSyntaxErrorException If the resource does not pass syntactic analysis
+ * @throws IOException When the resource cannot be read
+ * @throws IllegalArgumentException
+ * If input stream is not valid YANG stream
+ */
+ public static YangModelDependencyInfo forResource(final Class> refClass, final String resourceName)
+ throws IOException, YangSyntaxErrorException {
+ final YangStatementStreamSource source = YangStatementStreamSource.create(
+ YangTextSchemaSource.forResource(refClass, resourceName));
+ final ParserRuleContext ast = source.getYangAST();
+ checkArgument(ast instanceof StatementContext);
+ return parseAST((StatementContext) ast, source.getIdentifier().toYangFilename());
+ }
+
+ private static YangModelDependencyInfo parseModuleContext(final StatementContext module, final String sourceName) {
+ final String name = Utils.stringFromStringContext(module.argument(), getReference(sourceName, module));
+ final String latestRevision = getLatestRevision(module, sourceName);
+ final Optional semVer = Optional.ofNullable(findSemanticVersion(module, sourceName));
+ final ImmutableSet imports = parseImports(module, sourceName);
+ final ImmutableSet includes = parseIncludes(module, sourceName);
+
+ return new ModuleDependencyInfo(name, latestRevision, imports, includes, semVer);
+ }
+
+ private static ImmutableSet parseImports(final StatementContext module, final String sourceName) {
+ final Set result = new HashSet<>();
+ for (final StatementContext subStatementContext : module.statement()) {
+ if (IMPORT.equals(subStatementContext.keyword().getText())) {
+ final String revisionDateStr = getRevisionDateString(subStatementContext, sourceName);
+ final String importedModuleName = Utils.stringFromStringContext(subStatementContext.argument(),
+ getReference(sourceName, subStatementContext));
+ final Revision revisionDate = revisionDateStr == null ? null : Revision.valueOf(revisionDateStr);
+ final SemVer importSemVer = findSemanticVersion(subStatementContext, sourceName);
+ result.add(new ModuleImportImpl(importedModuleName, revisionDate, importSemVer));
+ }
}
- throw new IllegalArgumentException("Supplied stream is not valid yang file.");
+ return ImmutableSet.copyOf(result);
}
- private static YangModelDependencyInfo fromModuleContext(final 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());
+ private static SemVer findSemanticVersion(final StatementContext statement, final String sourceName) {
+ String semVerString = null;
+ for (final StatementContext subStatement : statement.statement()) {
+ final String subStatementName = Utils.trimPrefix(subStatement.keyword().getText());
+ if (OPENCONFIG_VERSION.equals(subStatementName)) {
+ semVerString = Utils.stringFromStringContext(subStatement.argument(),
+ getReference(sourceName, subStatement));
+ break;
+ }
+ }
+
+ return Strings.isNullOrEmpty(semVerString) ? null : SemVer.valueOf(semVerString);
+ }
- return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes);
+ private static ImmutableSet parseIncludes(final StatementContext module, final String sourceName) {
+ final Set result = new HashSet<>();
+ for (final StatementContext subStatementContext : module.statement()) {
+ if (INCLUDE.equals(subStatementContext.keyword().getText())) {
+ final String revisionDateStr = getRevisionDateString(subStatementContext, sourceName);
+ final String IncludeModuleName = Utils.stringFromStringContext(subStatementContext.argument(),
+ getReference(sourceName, subStatementContext));
+ final Revision revisionDate = revisionDateStr == null ? null : Revision.valueOf(revisionDateStr);
+ result.add(new ModuleImportImpl(IncludeModuleName, revisionDate));
+ }
+ }
+ return ImmutableSet.copyOf(result);
}
- private static ImmutableSet getImports(final List importStatements) {
- ImmutableSet.Builder builder = ImmutableSet.builder();
- for (Import_stmtContext importStmt : importStatements) {
- String moduleName = getArgumentString(importStmt);
- Date revision = getRevision(importStmt.revision_date_stmt());
- builder.add(new ModuleImportImpl(moduleName, revision));
+ private static String getRevisionDateString(final StatementContext importStatement, final String sourceName) {
+ String revisionDateStr = null;
+ for (final StatementContext importSubStatement : importStatement.statement()) {
+ if (REVISION_DATE.equals(importSubStatement.keyword().getText())) {
+ revisionDateStr = Utils.stringFromStringContext(importSubStatement.argument(),
+ getReference(sourceName, importSubStatement));
+ }
}
- return builder.build();
+ return revisionDateStr;
}
- private static String getLatestRevision(final Revision_stmtsContext revision_stmts) {
- List revisions = revision_stmts.getRuleContexts(Revision_stmtContext.class);
+ public static String getLatestRevision(final StatementContext module, final String sourceName) {
String latestRevision = null;
- for (Revision_stmtContext revisionStmt : revisions) {
- String currentRevision = getArgumentString(revisionStmt);
- if (latestRevision == null || latestRevision.compareTo(currentRevision) == -1) {
- latestRevision = currentRevision;
+ for (final StatementContext subStatementContext : module.statement()) {
+ if (REVISION.equals(subStatementContext.keyword().getText())) {
+ final String currentRevision = Utils.stringFromStringContext(subStatementContext.argument(),
+ getReference(sourceName, subStatementContext));
+ if (latestRevision == null || latestRevision.compareTo(currentRevision) == -1) {
+ latestRevision = currentRevision;
+ }
}
}
return latestRevision;
}
- private static YangModelDependencyInfo fromSubmoduleContext(final Submodule_stmtContext submodule) {
- String name = getArgumentString(submodule);
- Belongs_to_stmtContext belongsToStmt = submodule.submodule_header_stmts().belongs_to_stmt(0);
- String belongsTo = getArgumentString(belongsToStmt);
+ private static YangModelDependencyInfo parseSubmoduleContext(final StatementContext submodule,
+ final String sourceName) {
+ final String name = Utils.stringFromStringContext(submodule.argument(), getReference(sourceName, submodule));
+ final String belongsTo = parseBelongsTo(submodule, sourceName);
- String latestRevision = getLatestRevision(submodule.revision_stmts());
- ImmutableSet imports = getImports(submodule.linkage_stmts().import_stmt());
- ImmutableSet includes = getIncludes(submodule.linkage_stmts().include_stmt());
+ final String latestRevision = getLatestRevision(submodule, sourceName);
+ final ImmutableSet imports = parseImports(submodule, sourceName);
+ final ImmutableSet includes = parseIncludes(submodule, sourceName);
return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes);
}
- private static ImmutableSet getIncludes(final 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));
+ private static String parseBelongsTo(final StatementContext submodule, final String sourceName) {
+ for (final StatementContext subStatementContext : submodule.statement()) {
+ if (BELONGS_TO.equals(subStatementContext.keyword().getText())) {
+ return Utils.stringFromStringContext(subStatementContext.argument(),
+ getReference(sourceName, subStatementContext));
+ }
}
- return builder.build();
+ return null;
}
- private static Date getRevision(final Revision_date_stmtContext revision_date_stmt) {
- if (revision_date_stmt == null) {
- return null;
- }
- String formatedDate = getArgumentString(revision_date_stmt);
- return QName.parseRevision(formatedDate);
+ private static StatementSourceReference getReference(final String sourceName,
+ final StatementContext context) {
+ return DeclarationInTextSource.atPosition(sourceName, context.getStart().getLine(),
+ context.getStart().getCharPositionInLine());
}
- public static final class ModuleDependencyInfo extends YangModelDependencyInfo {
-
- private ModuleDependencyInfo(final String name, final String latestRevision, final String namespace,
+ /**
+ * Dependency information for YANG module.
+ */
+ public static class ModuleDependencyInfo extends YangModelDependencyInfo {
+ private ModuleDependencyInfo(final String name, final String latestRevision,
final ImmutableSet imports, final ImmutableSet includes) {
super(name, latestRevision, imports, includes);
}
+ private ModuleDependencyInfo(final String name, final String latestRevision,
+ final ImmutableSet imports,
+ final ImmutableSet includes,
+ final Optional semVer) {
+ super(name, latestRevision, imports, includes, semVer);
+ }
+
@Override
public String toString() {
return "Module [name=" + getName() + ", revision=" + getRevision()
- + ", dependencies=" + getDependencies() + "]";
+ + ", semanticVersion=" + getSemanticVersion().orElse(null)
+ + ", dependencies=" + getDependencies()
+ + "]";
}
}
+ /**
+ * Dependency information for submodule, also provides name for parent module.
+ */
public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo {
-
private final String belongsTo;
- public String getParentModule() {
- return belongsTo;
- }
-
private SubmoduleDependencyInfo(final String name, final String latestRevision, final String belongsTo,
final ImmutableSet imports, final ImmutableSet includes) {
super(name, latestRevision, imports, includes);
this.belongsTo = belongsTo;
}
+ /**
+ * Returns name of parent module.
+ */
+ public String getParentModule() {
+ return belongsTo;
+ }
+
@Override
public String toString() {
- return "Submodule [name=" + getName() + ", revision=" + getRevision()
- + ", dependencies=" + getDependencies() + "]";
+ return "Submodule [name=" + getName() + ", revision="
+ + getRevision() + ", dependencies=" + getDependencies()
+ + "]";
}
}
+ /**
+ * Utility implementation of {@link ModuleImport} to be used by {@link YangModelDependencyInfo}.
+ */
private static final class ModuleImportImpl implements ModuleImport {
- private final Date revision;
+ private final Revision revision;
+ private final SemVer semVer;
private final String name;
- public ModuleImportImpl(final String moduleName, final Date revision) {
- this.name = moduleName;
+ ModuleImportImpl(final String moduleName, final Revision revision) {
+ this(moduleName, revision, null);
+ }
+
+ ModuleImportImpl(final String moduleName, @Nullable final Revision revision, @Nullable final SemVer semVer) {
+ this.name = requireNonNull(moduleName, "Module name must not be null.");
this.revision = revision;
+ this.semVer = semVer;
}
@Override
public String getModuleName() {
- return this.name;
+ return name;
+ }
+
+ @Override
+ public Optional getRevision() {
+ return Optional.ofNullable(revision);
}
@Override
- public Date getRevision() {
- return this.revision;
+ public Optional getSemanticVersion() {
+ return Optional.ofNullable(semVer);
}
@Override
@@ -248,8 +423,9 @@ public abstract class YangModelDependencyInfo {
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());
+ result = prime * result + Objects.hashCode(name);
+ result = prime * result + Objects.hashCode(revision);
+ result = prime * result + Objects.hashCode(semVer);
return result;
}
@@ -264,7 +440,7 @@ public abstract class YangModelDependencyInfo {
if (getClass() != obj.getClass()) {
return false;
}
- ModuleImportImpl other = (ModuleImportImpl) obj;
+ final ModuleImportImpl other = (ModuleImportImpl) obj;
if (name == null) {
if (other.name != null) {
return false;
@@ -279,12 +455,17 @@ public abstract class YangModelDependencyInfo {
} else if (!revision.equals(other.revision)) {
return false;
}
+
+ if (!Objects.equals(getSemanticVersion(), other.getSemanticVersion())) {
+ return false;
+ }
return true;
}
@Override
public String toString() {
- return "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]";
+ return "ModuleImportImpl [name=" + name + ", revision="
+ + QName.formattedRevision(Optional.ofNullable(revision)) + ", semanticVersion=" + semVer + "]";
}
}
}