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=e92fb61edf292edb66cba5f65667080508920740;hb=e403e34bcb508c48aa606a1cd81a386fb73c5db6;hp=46c2f8240d3cb08f8eb28cce17da647125ebc0df;hpb=4aa42c049f6a0f1cc7442ef612006e3790d3eeb5;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 46c2f8240d..e92fb61edf 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 @@ -1,19 +1,24 @@ /* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * * 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.impl.ParserListenerUtils.getArgumentString; -import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getFirstContext; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import java.io.InputStream; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Objects; +import java.util.Set; import org.antlr.v4.runtime.ParserRuleContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext; @@ -23,11 +28,18 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmt 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.antlrv4.code.gen.YangStatementParser; +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.model.api.Module; import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.SupportedExtensionsMapping; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; /** * Helper transfer object which holds basic and dependency information for YANG @@ -45,33 +57,43 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; * @see SubmoduleDependencyInfo * */ + public abstract class YangModelDependencyInfo { private final String name; private final String formattedRevision; private final Date revision; + private final Optional semVer; private final ImmutableSet submoduleIncludes; private final ImmutableSet moduleImports; private final ImmutableSet dependencies; YangModelDependencyInfo(final String name, final String formattedRevision, - final ImmutableSet imports, final ImmutableSet includes) { + final ImmutableSet imports, + final ImmutableSet includes) { + this(name, formattedRevision, imports, includes, Optional.absent()); + } + + YangModelDependencyInfo(final String name, final String formattedRevision, + final ImmutableSet imports, + final ImmutableSet includes, + final Optional semVer) { this.name = name; this.formattedRevision = formattedRevision; - this.revision = formattedRevision == null ? null : QName.parseRevision(formattedRevision); + this.revision = formattedRevision == null ? null : QName + .parseRevision(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. + * This collection contains both import statements and + * include statements for submodules. * * @return Immutable collection of imports. */ @@ -106,12 +128,22 @@ public abstract class YangModelDependencyInfo { 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; } @@ -126,7 +158,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; @@ -141,25 +173,39 @@ public abstract class YangModelDependencyInfo { } else if (!name.equals(other.name)) { return false; } + if(!Objects.equals(semVer, other.semVer)) { + return false; + } + return true; } /** - * Extracts {@link YangModelDependencyInfo} from an abstract syntax tree - * of a YANG model. + * Extracts {@link YangModelDependencyInfo} from an abstract syntax tree of + * a YANG model. * - * @param tree Abstract syntax tree + * @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 { - final Optional moduleCtx = getFirstContext(tree, Module_stmtContext.class); + public static YangModelDependencyInfo fromAST(final String name, + final ParserRuleContext tree) throws YangSyntaxErrorException { + + if (tree instanceof YangStatementParser.StatementContext) { + final YangStatementParser.StatementContext rootStatement = (YangStatementParser.StatementContext) tree; + return parseAST(rootStatement); + } + + final Optional moduleCtx = ParserListenerUtils + .getFirstContext(tree, Module_stmtContext.class); if (moduleCtx.isPresent()) { return parseModuleContext(moduleCtx.get()); } - final Optional submoduleCtx = getFirstContext(tree, Submodule_stmtContext.class); + final Optional submoduleCtx = ParserListenerUtils + .getFirstContext(tree, Submodule_stmtContext.class); if (submoduleCtx.isPresent()) { return parseSubmoduleContext(submoduleCtx.get()); } @@ -167,12 +213,31 @@ public abstract class YangModelDependencyInfo { throw new YangSyntaxErrorException(name, 0, 0, "Unknown YANG text type"); } + private static YangModelDependencyInfo parseAST( + final YangStatementParser.StatementContext rootStatement) { + if (rootStatement + .keyword() + .getText() + .equals(Rfc6020Mapping.MODULE.getStatementName().getLocalName())) { + return parseModuleContext(rootStatement); + } else if (rootStatement + .keyword() + .getText() + .equals(Rfc6020Mapping.SUBMODULE.getStatementName() + .getLocalName())) { + return parseSubmoduleContext(rootStatement); + } + + throw new IllegalArgumentException( + "Root of parsed AST must be either module or submodule"); + } + /** - * Extracts {@link YangModelDependencyInfo} from input stream - * containing YANG model. + * Extracts {@link YangModelDependencyInfo} from input stream containing + * YANG model. * - * This parsing does not validate full YANG module, only - * parses header up to the revisions and imports. + * This parsing does not validate full YANG module, only parses header up to + * the revisions and imports. * * @param yangStream * Opened Input stream containing text source of YANG model @@ -180,78 +245,225 @@ public abstract class YangModelDependencyInfo { * @throws IllegalArgumentException * If input stream is not valid YANG stream */ - public static YangModelDependencyInfo fromInputStream(final InputStream yangStream) { - YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream); + public static YangModelDependencyInfo fromInputStream( + final InputStream yangStream) { + final StatementContext yangAST = new YangStatementSourceImpl(yangStream) + .getYangAST(); + return parseAST(yangAST); + } - Optional moduleCtx = getFirstContext(yangContext, Module_stmtContext.class); - if (moduleCtx.isPresent()) { - return parseModuleContext(moduleCtx.get()); + private static YangModelDependencyInfo parseModuleContext( + final Module_stmtContext module) { + final String name = getArgumentString(module); + final String latestRevision = getLatestRevision(module.revision_stmts()); + final ImmutableSet imports = parseImports(module + .linkage_stmts().import_stmt()); + final ImmutableSet includes = parseIncludes(module + .linkage_stmts().include_stmt()); + + return new ModuleDependencyInfo(name, latestRevision, imports, includes); + } + + private static YangModelDependencyInfo parseModuleContext( + final YangStatementParser.StatementContext module) { + final String name = Utils.stringFromStringContext(module.argument()); + final String latestRevision = getLatestRevision(module); + final Optional semVer = Optional.fromNullable(getSemanticVersion(module)); + final ImmutableSet imports = parseImports(module); + final ImmutableSet includes = parseIncludes(module); + + return new ModuleDependencyInfo(name, latestRevision, imports, includes, semVer); + } + + private static ImmutableSet parseImports( + final YangStatementParser.StatementContext module) { + final Set result = new HashSet<>(); + final List subStatements = module.statement(); + for (final StatementContext subStatementContext : subStatements) { + if (subStatementContext + .keyword() + .getText() + .equals(Rfc6020Mapping.IMPORT.getStatementName() + .getLocalName())) { + final String revisionDateStr = getRevisionDateString(subStatementContext); + final String importedModuleName = Utils + .stringFromStringContext(subStatementContext.argument()); + final Date revisionDate = (revisionDateStr == null) ? null : QName + .parseRevision(revisionDateStr); + final Optional importSemVer = Optional.fromNullable(getSemanticVersion(subStatementContext)); + result.add(new ModuleImportImpl(importedModuleName, + revisionDate, importSemVer)); + } } - Optional submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class); - if (submoduleCtx.isPresent()) { - return parseSubmoduleContext(submoduleCtx.get()); + return ImmutableSet.copyOf(result); + } + + private static SemVer getSemanticVersion(final StatementContext statement) { + final List subStatements = statement.statement(); + String semVerString = null; + final String semVerStmtName = SupportedExtensionsMapping.SEMANTIC_VERSION.getStatementName().getLocalName(); + for (final StatementContext subStatement : subStatements) { + final String subStatementName = Utils.trimPrefix(subStatement.keyword().getText()); + if (semVerStmtName.equals(subStatementName)) { + semVerString = Utils.stringFromStringContext(subStatement.argument()); + break; + } + } + + if (Strings.isNullOrEmpty(semVerString)) { + return null; } - throw new IllegalArgumentException("Supplied stream is not valid yang file."); + + return SemVer.valueOf(semVerString); } - private static YangModelDependencyInfo parseModuleContext(final Module_stmtContext module) { - String name = getArgumentString(module); - String latestRevision = getLatestRevision(module.revision_stmts()); - ImmutableSet imports = parseImports(module.linkage_stmts().import_stmt()); - ImmutableSet includes = parseIncludes(module.linkage_stmts().include_stmt()); + private static ImmutableSet parseIncludes( + final YangStatementParser.StatementContext module) { + final Set result = new HashSet<>(); + final List subStatements = module.statement(); + for (final StatementContext subStatementContext : subStatements) { + if (subStatementContext + .keyword() + .getText() + .equals(Rfc6020Mapping.INCLUDE.getStatementName() + .getLocalName())) { + final String revisionDateStr = getRevisionDateString(subStatementContext); + final String IncludeModuleName = Utils + .stringFromStringContext(subStatementContext.argument()); + final Date revisionDate = (revisionDateStr == null) ? null : QName + .parseRevision(revisionDateStr); + result.add(new ModuleImportImpl(IncludeModuleName, revisionDate)); + } + } + return ImmutableSet.copyOf(result); + } - return new ModuleDependencyInfo(name, latestRevision, imports, includes); + private static String getRevisionDateString(final StatementContext importStatement) { + final List importSubStatements = importStatement + .statement(); + String revisionDateStr = null; + for (final StatementContext importSubStatement : importSubStatements) { + if (importSubStatement + .keyword() + .getText() + .equals(Rfc6020Mapping.REVISION_DATE.getStatementName() + .getLocalName())) { + revisionDateStr = Utils + .stringFromStringContext(importSubStatement.argument()); + } + } + return revisionDateStr; } - private static ImmutableSet parseImports(final List importStatements) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Import_stmtContext importStmt : importStatements) { - String moduleName = getArgumentString(importStmt); - Date revision = getRevision(importStmt.revision_date_stmt()); + private static ImmutableSet parseImports( + final List importStatements) { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (final Import_stmtContext importStmt : importStatements) { + final String moduleName = getArgumentString(importStmt); + final Date revision = getRevision(importStmt.revision_date_stmt()); builder.add(new ModuleImportImpl(moduleName, revision)); } return builder.build(); } - public static String getLatestRevision(final Revision_stmtsContext revision_stmts) { - List revisions = revision_stmts.getRuleContexts(Revision_stmtContext.class); + public static String getLatestRevision( + final YangStatementParser.StatementContext module) { + final List subStatements = module.statement(); + String latestRevision = null; + for (final StatementContext subStatementContext : subStatements) { + if (subStatementContext + .keyword() + .getText() + .equals(Rfc6020Mapping.REVISION.getStatementName() + .getLocalName())) { + final String currentRevision = Utils + .stringFromStringContext(subStatementContext.argument()); + if (latestRevision == null + || latestRevision.compareTo(currentRevision) == -1) { + latestRevision = currentRevision; + } + } + } + return latestRevision; + } + + public static String getLatestRevision( + final Revision_stmtsContext revisionStmts) { + final List revisions = revisionStmts + .getRuleContexts(Revision_stmtContext.class); String latestRevision = null; - for (Revision_stmtContext revisionStmt : revisions) { - String currentRevision = getArgumentString(revisionStmt); - if (latestRevision == null || latestRevision.compareTo(currentRevision) == -1) { + for (final Revision_stmtContext revisionStmt : revisions) { + final String currentRevision = getArgumentString(revisionStmt); + if (latestRevision == null + || latestRevision.compareTo(currentRevision) == -1) { latestRevision = currentRevision; } } return latestRevision; } - private static YangModelDependencyInfo parseSubmoduleContext(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 YangStatementParser.StatementContext submodule) { + final String name = Utils.stringFromStringContext(submodule.argument()); + final String belongsTo = parseBelongsTo(submodule); + + final String latestRevision = getLatestRevision(submodule); + final ImmutableSet imports = parseImports(submodule); + final ImmutableSet includes = parseIncludes(submodule); - String latestRevision = getLatestRevision(submodule.revision_stmts()); - ImmutableSet imports = parseImports(submodule.linkage_stmts().import_stmt()); - ImmutableSet includes = parseIncludes(submodule.linkage_stmts().include_stmt()); + return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, + imports, includes); + } + + private static String parseBelongsTo(final StatementContext submodule) { + final List subStatements = submodule.statement(); + for (final StatementContext subStatementContext : subStatements) { + if (subStatementContext + .keyword() + .getText() + .equals(Rfc6020Mapping.BELONGS_TO.getStatementName() + .getLocalName())) { + return Utils.stringFromStringContext(subStatementContext + .argument()); + } + } + return null; + } - return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes); + private static YangModelDependencyInfo parseSubmoduleContext( + final Submodule_stmtContext submodule) { + final String name = getArgumentString(submodule); + final Belongs_to_stmtContext belongsToStmt = submodule + .submodule_header_stmts().belongs_to_stmt(0); + final String belongsTo = getArgumentString(belongsToStmt); + + final String latestRevision = getLatestRevision(submodule.revision_stmts()); + final ImmutableSet imports = parseImports(submodule + .linkage_stmts().import_stmt()); + final ImmutableSet includes = parseIncludes(submodule + .linkage_stmts().include_stmt()); + + return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, + imports, includes); } - private static ImmutableSet parseIncludes(final List importStatements) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Include_stmtContext importStmt : importStatements) { - String moduleName = getArgumentString(importStmt); - Date revision = getRevision(importStmt.revision_date_stmt()); + private static ImmutableSet parseIncludes( + final List importStatements) { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (final Include_stmtContext importStmt : importStatements) { + final String moduleName = getArgumentString(importStmt); + final Date revision = getRevision(importStmt.revision_date_stmt()); builder.add(new ModuleImportImpl(moduleName, revision)); } return builder.build(); } - private static Date getRevision(final Revision_date_stmtContext revision_date_stmt) { - if (revision_date_stmt == null) { + private static Date getRevision( + final Revision_date_stmtContext revisionDateStmt) { + if (revisionDateStmt == null) { return null; } - String formatedDate = getArgumentString(revision_date_stmt); + final String formatedDate = getArgumentString(revisionDateStmt); return QName.parseRevision(formatedDate); } @@ -260,30 +472,51 @@ public abstract class YangModelDependencyInfo { * Dependency information for YANG module. * */ - public static final class ModuleDependencyInfo extends YangModelDependencyInfo { + public static class ModuleDependencyInfo extends + YangModelDependencyInfo { - private ModuleDependencyInfo(final String name, final String latestRevision, - final ImmutableSet imports, final ImmutableSet includes) { + 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() + return "Module [name=" + getName() + ", revision=" + getRevision() + ", semanticVersion=" + + getSemanticVersion().or(Module.DEFAULT_SEMANTIC_VERSION) + ", dependencies=" + getDependencies() + "]"; } } /** * - * Dependency information for submodule, also provides name - * for parent module. + * Dependency information for submodule, also provides name for parent + * module. * */ - public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo { + public static final class SubmoduleDependencyInfo extends + YangModelDependencyInfo { private final String 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. * @@ -292,16 +525,11 @@ public abstract class YangModelDependencyInfo { 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; - } - @Override public String toString() { - return "Submodule [name=" + getName() + ", revision=" + getRevision() + ", dependencies=" - + getDependencies() + "]"; + return "Submodule [name=" + getName() + ", revision=" + + getRevision() + ", dependencies=" + getDependencies() + + "]"; } } @@ -313,11 +541,17 @@ public abstract class YangModelDependencyInfo { private static final class ModuleImportImpl implements ModuleImport { private final Date revision; + private final SemVer semVer; private final String name; public ModuleImportImpl(final String moduleName, final Date revision) { - this.name = moduleName; + this(moduleName, revision, Optional.absent()); + } + + public ModuleImportImpl(final String moduleName, final Date revision, final Optional semVer) { + this.name = Preconditions.checkNotNull(moduleName, "Module name must not be null."); this.revision = revision; + this.semVer = semVer.or(Module.DEFAULT_SEMANTIC_VERSION); } @Override @@ -330,6 +564,11 @@ public abstract class YangModelDependencyInfo { return this.revision; } + @Override + public SemVer getSemanticVersion() { + return this.semVer; + } + @Override public String getPrefix() { return null; @@ -339,8 +578,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; } @@ -355,7 +595,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; @@ -370,12 +610,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(revision) + ", semanticVersion=" + getSemanticVersion() + "]"; } } }