Bug 4662: Introduce a SemanticVersion concept - SchemaContextFactory
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / util / YangModelDependencyInfo.java
index e7125bf4ad5d210d884ec60b6d66e1dfb080251e..e92fb61edf292edb66cba5f65667080508920740 100644 (file)
@@ -11,6 +11,7 @@ import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.ge
 
 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;
@@ -36,6 +37,7 @@ 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.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;
 
@@ -61,6 +63,7 @@ public abstract class YangModelDependencyInfo {
     private final String name;
     private final String formattedRevision;
     private final Date revision;
+    private final Optional<SemVer> semVer;
     private final ImmutableSet<ModuleImport> submoduleIncludes;
     private final ImmutableSet<ModuleImport> moduleImports;
     private final ImmutableSet<ModuleImport> dependencies;
@@ -68,6 +71,13 @@ public abstract class YangModelDependencyInfo {
     YangModelDependencyInfo(final String name, final String formattedRevision,
             final ImmutableSet<ModuleImport> imports,
             final ImmutableSet<ModuleImport> includes) {
+        this(name, formattedRevision, imports, includes, Optional.absent());
+    }
+
+    YangModelDependencyInfo(final String name, final String formattedRevision,
+            final ImmutableSet<ModuleImport> imports,
+            final ImmutableSet<ModuleImport> includes,
+            final Optional<SemVer> semVer) {
         this.name = name;
         this.formattedRevision = formattedRevision;
         this.revision = formattedRevision == null ? null : QName
@@ -76,6 +86,7 @@ public abstract class YangModelDependencyInfo {
         this.submoduleIncludes = includes;
         this.dependencies = ImmutableSet.<ModuleImport> builder()
                 .addAll(moduleImports).addAll(submoduleIncludes).build();
+        this.semVer = semVer;
     }
 
     /**
@@ -117,12 +128,22 @@ public abstract class YangModelDependencyInfo {
         return revision;
     }
 
+    /**
+     * Returns semantic version of module
+     *
+     * @return semantic version
+     */
+    public Optional<SemVer> getSemanticVersion() {
+        return semVer;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + Objects.hashCode(formattedRevision);
         result = prime * result + Objects.hashCode(name);
+        result = prime * result + Objects.hashCode(semVer);
         return result;
     }
 
@@ -137,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;
@@ -152,6 +173,10 @@ public abstract class YangModelDependencyInfo {
         } else if (!name.equals(other.name)) {
             return false;
         }
+        if(!Objects.equals(semVer, other.semVer)) {
+            return false;
+        }
+
         return true;
     }
 
@@ -169,7 +194,7 @@ public abstract class YangModelDependencyInfo {
             final ParserRuleContext tree) throws YangSyntaxErrorException {
 
         if (tree instanceof YangStatementParser.StatementContext) {
-            YangStatementParser.StatementContext rootStatement = (YangStatementParser.StatementContext) tree;
+            final YangStatementParser.StatementContext rootStatement = (YangStatementParser.StatementContext) tree;
             return parseAST(rootStatement);
         }
 
@@ -189,7 +214,7 @@ public abstract class YangModelDependencyInfo {
     }
 
     private static YangModelDependencyInfo parseAST(
-            YangStatementParser.StatementContext rootStatement) {
+            final YangStatementParser.StatementContext rootStatement) {
         if (rootStatement
                 .keyword()
                 .getText()
@@ -222,18 +247,18 @@ public abstract class YangModelDependencyInfo {
      */
     public static YangModelDependencyInfo fromInputStream(
             final InputStream yangStream) {
-        StatementContext yangAST = new YangStatementSourceImpl(yangStream)
+        final StatementContext yangAST = new YangStatementSourceImpl(yangStream)
                 .getYangAST();
         return parseAST(yangAST);
     }
 
     private static YangModelDependencyInfo parseModuleContext(
             final Module_stmtContext module) {
-        String name = getArgumentString(module);
-        String latestRevision = getLatestRevision(module.revision_stmts());
-        ImmutableSet<ModuleImport> imports = parseImports(module
+        final String name = getArgumentString(module);
+        final String latestRevision = getLatestRevision(module.revision_stmts());
+        final ImmutableSet<ModuleImport> imports = parseImports(module
                 .linkage_stmts().import_stmt());
-        ImmutableSet<ModuleImport> includes = parseIncludes(module
+        final ImmutableSet<ModuleImport> includes = parseIncludes(module
                 .linkage_stmts().include_stmt());
 
         return new ModuleDependencyInfo(name, latestRevision, imports, includes);
@@ -241,50 +266,71 @@ public abstract class YangModelDependencyInfo {
 
     private static YangModelDependencyInfo parseModuleContext(
             final YangStatementParser.StatementContext module) {
-        String name = Utils.stringFromStringContext(module.argument());
-        String latestRevision = getLatestRevision(module);
-        ImmutableSet<ModuleImport> imports = parseImports(module);
-        ImmutableSet<ModuleImport> includes = parseIncludes(module);
+        final String name = Utils.stringFromStringContext(module.argument());
+        final String latestRevision = getLatestRevision(module);
+        final Optional<SemVer> semVer = Optional.fromNullable(getSemanticVersion(module));
+        final ImmutableSet<ModuleImport> imports = parseImports(module);
+        final ImmutableSet<ModuleImport> includes = parseIncludes(module);
 
-        return new ModuleDependencyInfo(name, latestRevision, imports, includes);
+        return new ModuleDependencyInfo(name, latestRevision, imports, includes, semVer);
     }
 
     private static ImmutableSet<ModuleImport> parseImports(
             final YangStatementParser.StatementContext module) {
-        Set<ModuleImport> result = new HashSet<>();
-        List<StatementContext> subStatements = module.statement();
-        for (StatementContext subStatementContext : subStatements) {
+        final Set<ModuleImport> result = new HashSet<>();
+        final List<StatementContext> subStatements = module.statement();
+        for (final StatementContext subStatementContext : subStatements) {
             if (subStatementContext
                     .keyword()
                     .getText()
                     .equals(Rfc6020Mapping.IMPORT.getStatementName()
                             .getLocalName())) {
-                String revisionDateStr = getRevisionDateString(subStatementContext);
-                String importedModuleName = Utils
+                final String revisionDateStr = getRevisionDateString(subStatementContext);
+                final String importedModuleName = Utils
                         .stringFromStringContext(subStatementContext.argument());
-                Date revisionDate = (revisionDateStr == null) ? null : QName
+                final Date revisionDate = (revisionDateStr == null) ? null : QName
                         .parseRevision(revisionDateStr);
+                final Optional<SemVer> importSemVer = Optional.fromNullable(getSemanticVersion(subStatementContext));
                 result.add(new ModuleImportImpl(importedModuleName,
-                        revisionDate));
+                        revisionDate, importSemVer));
             }
         }
         return ImmutableSet.copyOf(result);
     }
 
+    private static SemVer getSemanticVersion(final StatementContext statement) {
+        final List<StatementContext> 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;
+        }
+
+        return SemVer.valueOf(semVerString);
+    }
+
     private static ImmutableSet<ModuleImport> parseIncludes(
             final YangStatementParser.StatementContext module) {
-        Set<ModuleImport> result = new HashSet<>();
-        List<StatementContext> subStatements = module.statement();
-        for (StatementContext subStatementContext : subStatements) {
+        final Set<ModuleImport> result = new HashSet<>();
+        final List<StatementContext> subStatements = module.statement();
+        for (final StatementContext subStatementContext : subStatements) {
             if (subStatementContext
                     .keyword()
                     .getText()
                     .equals(Rfc6020Mapping.INCLUDE.getStatementName()
                             .getLocalName())) {
-                String revisionDateStr = getRevisionDateString(subStatementContext);
-                String IncludeModuleName = Utils
+                final String revisionDateStr = getRevisionDateString(subStatementContext);
+                final String IncludeModuleName = Utils
                         .stringFromStringContext(subStatementContext.argument());
-                Date revisionDate = (revisionDateStr == null) ? null : QName
+                final Date revisionDate = (revisionDateStr == null) ? null : QName
                         .parseRevision(revisionDateStr);
                 result.add(new ModuleImportImpl(IncludeModuleName, revisionDate));
             }
@@ -292,11 +338,11 @@ public abstract class YangModelDependencyInfo {
         return ImmutableSet.copyOf(result);
     }
 
-    private static String getRevisionDateString(StatementContext importStatement) {
-        List<StatementContext> importSubStatements = importStatement
+    private static String getRevisionDateString(final StatementContext importStatement) {
+        final List<StatementContext> importSubStatements = importStatement
                 .statement();
         String revisionDateStr = null;
-        for (StatementContext importSubStatement : importSubStatements) {
+        for (final StatementContext importSubStatement : importSubStatements) {
             if (importSubStatement
                     .keyword()
                     .getText()
@@ -311,10 +357,10 @@ public abstract class YangModelDependencyInfo {
 
     private static ImmutableSet<ModuleImport> parseImports(
             final List<Import_stmtContext> importStatements) {
-        ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
-        for (Import_stmtContext importStmt : importStatements) {
-            String moduleName = getArgumentString(importStmt);
-            Date revision = getRevision(importStmt.revision_date_stmt());
+        final ImmutableSet.Builder<ModuleImport> 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();
@@ -322,15 +368,15 @@ public abstract class YangModelDependencyInfo {
 
     public static String getLatestRevision(
             final YangStatementParser.StatementContext module) {
-        List<StatementContext> subStatements = module.statement();
+        final List<StatementContext> subStatements = module.statement();
         String latestRevision = null;
-        for (StatementContext subStatementContext : subStatements) {
+        for (final StatementContext subStatementContext : subStatements) {
             if (subStatementContext
                     .keyword()
                     .getText()
                     .equals(Rfc6020Mapping.REVISION.getStatementName()
                             .getLocalName())) {
-                String currentRevision = Utils
+                final String currentRevision = Utils
                         .stringFromStringContext(subStatementContext.argument());
                 if (latestRevision == null
                         || latestRevision.compareTo(currentRevision) == -1) {
@@ -343,11 +389,11 @@ public abstract class YangModelDependencyInfo {
 
     public static String getLatestRevision(
             final Revision_stmtsContext revisionStmts) {
-        List<Revision_stmtContext> revisions = revisionStmts
+        final List<Revision_stmtContext> revisions = revisionStmts
                 .getRuleContexts(Revision_stmtContext.class);
         String latestRevision = null;
-        for (Revision_stmtContext revisionStmt : revisions) {
-            String currentRevision = getArgumentString(revisionStmt);
+        for (final Revision_stmtContext revisionStmt : revisions) {
+            final String currentRevision = getArgumentString(revisionStmt);
             if (latestRevision == null
                     || latestRevision.compareTo(currentRevision) == -1) {
                 latestRevision = currentRevision;
@@ -358,20 +404,20 @@ public abstract class YangModelDependencyInfo {
 
     private static YangModelDependencyInfo parseSubmoduleContext(
             final YangStatementParser.StatementContext submodule) {
-        String name = Utils.stringFromStringContext(submodule.argument());
-        String belongsTo = parseBelongsTo(submodule);
+        final String name = Utils.stringFromStringContext(submodule.argument());
+        final String belongsTo = parseBelongsTo(submodule);
 
-        String latestRevision = getLatestRevision(submodule);
-        ImmutableSet<ModuleImport> imports = parseImports(submodule);
-        ImmutableSet<ModuleImport> includes = parseIncludes(submodule);
+        final String latestRevision = getLatestRevision(submodule);
+        final ImmutableSet<ModuleImport> imports = parseImports(submodule);
+        final ImmutableSet<ModuleImport> includes = parseIncludes(submodule);
 
         return new SubmoduleDependencyInfo(name, latestRevision, belongsTo,
                 imports, includes);
     }
 
-    private static String parseBelongsTo(StatementContext submodule) {
-        List<StatementContext> subStatements = submodule.statement();
-        for (StatementContext subStatementContext : subStatements) {
+    private static String parseBelongsTo(final StatementContext submodule) {
+        final List<StatementContext> subStatements = submodule.statement();
+        for (final StatementContext subStatementContext : subStatements) {
             if (subStatementContext
                     .keyword()
                     .getText()
@@ -386,15 +432,15 @@ public abstract class YangModelDependencyInfo {
 
     private static YangModelDependencyInfo parseSubmoduleContext(
             final Submodule_stmtContext submodule) {
-        String name = getArgumentString(submodule);
-        Belongs_to_stmtContext belongsToStmt = submodule
+        final String name = getArgumentString(submodule);
+        final Belongs_to_stmtContext belongsToStmt = submodule
                 .submodule_header_stmts().belongs_to_stmt(0);
-        String belongsTo = getArgumentString(belongsToStmt);
+        final String belongsTo = getArgumentString(belongsToStmt);
 
-        String latestRevision = getLatestRevision(submodule.revision_stmts());
-        ImmutableSet<ModuleImport> imports = parseImports(submodule
+        final String latestRevision = getLatestRevision(submodule.revision_stmts());
+        final ImmutableSet<ModuleImport> imports = parseImports(submodule
                 .linkage_stmts().import_stmt());
-        ImmutableSet<ModuleImport> includes = parseIncludes(submodule
+        final ImmutableSet<ModuleImport> includes = parseIncludes(submodule
                 .linkage_stmts().include_stmt());
 
         return new SubmoduleDependencyInfo(name, latestRevision, belongsTo,
@@ -403,10 +449,10 @@ public abstract class YangModelDependencyInfo {
 
     private static ImmutableSet<ModuleImport> parseIncludes(
             final List<Include_stmtContext> importStatements) {
-        ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
-        for (Include_stmtContext importStmt : importStatements) {
-            String moduleName = getArgumentString(importStmt);
-            Date revision = getRevision(importStmt.revision_date_stmt());
+        final ImmutableSet.Builder<ModuleImport> 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();
@@ -417,7 +463,7 @@ public abstract class YangModelDependencyInfo {
         if (revisionDateStmt == null) {
             return null;
         }
-        String formatedDate = getArgumentString(revisionDateStmt);
+        final String formatedDate = getArgumentString(revisionDateStmt);
         return QName.parseRevision(formatedDate);
     }
 
@@ -426,7 +472,7 @@ public abstract class YangModelDependencyInfo {
      * Dependency information for YANG module.
      *
      */
-    public static final class ModuleDependencyInfo extends
+    public static class ModuleDependencyInfo extends
             YangModelDependencyInfo {
 
         private ModuleDependencyInfo(final String name,
@@ -436,10 +482,19 @@ public abstract class YangModelDependencyInfo {
             super(name, latestRevision, imports, includes);
         }
 
+        private ModuleDependencyInfo(final String name,
+                final String latestRevision,
+                final ImmutableSet<ModuleImport> imports,
+                final ImmutableSet<ModuleImport> includes,
+                final Optional<SemVer> 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()
+                    + "]";
         }
     }
 
@@ -490,13 +545,13 @@ public abstract class YangModelDependencyInfo {
         private final String name;
 
         public ModuleImportImpl(final String moduleName, final Date revision) {
-            this(moduleName, revision, Module.DEFAULT_SEMANTIC_VERSION);
+            this(moduleName, revision, Optional.absent());
         }
 
-        public ModuleImportImpl(final String moduleName, final Date revision, final SemVer semVer) {
+        public ModuleImportImpl(final String moduleName, final Date revision, final Optional<SemVer> semVer) {
             this.name = Preconditions.checkNotNull(moduleName, "Module name must not be null.");
             this.revision = revision;
-            this.semVer = Preconditions.checkNotNull(semVer, "Semantic version of module must not be null.");
+            this.semVer = semVer.or(Module.DEFAULT_SEMANTIC_VERSION);
         }
 
         @Override
@@ -540,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;
@@ -565,7 +620,7 @@ public abstract class YangModelDependencyInfo {
         @Override
         public String toString() {
             return "ModuleImportImpl [name=" + name + ", revision="
-                    + QName.formattedRevision(revision) + "]";
+                    + QName.formattedRevision(revision) + ", semanticVersion=" + getSemanticVersion() + "]";
         }
     }
 }