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 cbe259f1fd9fc1abedb2b0ee7aca82bd6b57a540..e92fb61edf292edb66cba5f65667080508920740 100644 (file)
@@ -9,21 +9,16 @@ package org.opendaylight.yangtools.yang.parser.impl.util;
 
 import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getArgumentString;
 
-import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils;
-
 import com.google.common.base.Optional;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
-import java.util.HashSet;
-import java.util.Set;
-import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
+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;
@@ -33,9 +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.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.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
@@ -59,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;
@@ -66,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
@@ -74,6 +86,7 @@ public abstract class YangModelDependencyInfo {
         this.submoduleIncludes = includes;
         this.dependencies = ImmutableSet.<ModuleImport> builder()
                 .addAll(moduleImports).addAll(submoduleIncludes).build();
+        this.semVer = semVer;
     }
 
     /**
@@ -115,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;
     }
 
@@ -135,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;
@@ -150,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;
     }
 
@@ -167,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);
         }
 
@@ -187,7 +214,7 @@ public abstract class YangModelDependencyInfo {
     }
 
     private static YangModelDependencyInfo parseAST(
-            YangStatementParser.StatementContext rootStatement) {
+            final YangStatementParser.StatementContext rootStatement) {
         if (rootStatement
                 .keyword()
                 .getText()
@@ -220,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);
@@ -239,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));
             }
@@ -290,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()
@@ -309,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();
@@ -320,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) {
@@ -341,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;
@@ -356,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()
@@ -384,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,
@@ -401,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();
@@ -415,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);
     }
 
@@ -424,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,
@@ -434,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()
+                    + "]";
         }
     }
 
@@ -484,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> semVer) {
+            this.name = Preconditions.checkNotNull(moduleName, "Module name must not be null.");
             this.revision = revision;
+            this.semVer = semVer.or(Module.DEFAULT_SEMANTIC_VERSION);
         }
 
         @Override
@@ -501,6 +564,11 @@ public abstract class YangModelDependencyInfo {
             return this.revision;
         }
 
+        @Override
+        public SemVer getSemanticVersion() {
+            return this.semVer;
+        }
+
         @Override
         public String getPrefix() {
             return null;
@@ -512,6 +580,7 @@ public abstract class YangModelDependencyInfo {
             int result = 1;
             result = prime * result + Objects.hashCode(name);
             result = prime * result + Objects.hashCode(revision);
+            result = prime * result + Objects.hashCode(semVer);
             return result;
         }
 
@@ -526,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;
@@ -541,13 +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) + "]";
+                    + QName.formattedRevision(revision) + ", semanticVersion=" + getSemanticVersion() + "]";
         }
     }
 }