Bug 4662: Introduce a SemanticVersion concept - SchemaContextFactory 22/37622/28
authorPeter Kajsa <pkajsa@cisco.com>
Thu, 14 Apr 2016 09:28:29 +0000 (11:28 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 6 Jun 2016 17:20:46 +0000 (17:20 +0000)
Introducing of semantic version concept into SchemaContextFactory.

Change-Id: I382d6d6107852cd39a8e4023bbf2ae4d079782c7
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
27 files changed:
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/RevisionSourceIdentifier.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SemVerSourceIdentifier.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCache.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCacheTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCacheTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/RevisionDependencyResolver.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SemVerDependencyResolver.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolverTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SemVerSharedSchemaRepositoryTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactoryTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryTest.java
yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/semantic-version.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/bar@2016-01-01.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/semantic-version.yang [new file with mode: 0644]

diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/RevisionSourceIdentifier.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/RevisionSourceIdentifier.java
new file mode 100644 (file)
index 0000000..b12b236
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016 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/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.util.Objects;
+
+/**
+ * YANG Schema revision source identifier
+ *
+ * Simple transfer object represents revision identifier of source for YANG
+ * schema (module or submodule), which consists of
+ * <ul>
+ * <li>YANG schema name ({@link #getName()}
+ * <li>Module revision (optional) ({link {@link #getRevision()})
+ * </ul>
+ *
+ * Revision source identifier is designated to be carry only necessary
+ * information to look-up YANG model source and to be used by various
+ * SchemaSourceProviders.
+ *
+ * <b>Note:</b>On source retrieval layer it is impossible to distinguish between
+ * YANG module and/or submodule unless source is present.
+ *
+ * <p>
+ * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2
+ * and http://tools.ietf.org/html/rfc6022#section-3.1 ).
+ */
+@Beta
+public final class RevisionSourceIdentifier extends SourceIdentifier {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     * Creates new YANG Schema revision source identifier for sources without
+     * revision. {@link SourceIdentifier#NOT_PRESENT_FORMATTED_REVISION} as
+     * default revision.
+     *
+     * @param name
+     *            Name of schema
+     */
+    RevisionSourceIdentifier(final String name) {
+        this(name, NOT_PRESENT_FORMATTED_REVISION);
+    }
+
+    /**
+     * Creates new YANG Schema revision source identifier.
+     *
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Revision of source in format YYYY-mm-dd
+     */
+    RevisionSourceIdentifier(final String name, final String formattedRevision) {
+        super(Preconditions.checkNotNull(name), Preconditions.checkNotNull(formattedRevision));
+    }
+
+    /**
+     *
+     * Creates new YANG Schema revision source identifier.
+     *
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Revision of source in format YYYY-mm-dd. If not present,
+     *            default value will be used.
+     */
+    RevisionSourceIdentifier(final String name, final Optional<String> formattedRevision) {
+        this(name, formattedRevision.or(NOT_PRESENT_FORMATTED_REVISION));
+    }
+
+    /**
+     *
+     * Creates new YANG Schema revision source identifier.
+     *
+     * @param moduleName
+     *            Name of schema
+     * @param revision
+     *            Revision of source in format YYYY-mm-dd. If not present,
+     *            default value will be used.
+     */
+    public static RevisionSourceIdentifier create(final String moduleName,
+            final Optional<String> revision) {
+        return new RevisionSourceIdentifier(moduleName, revision);
+    }
+
+    /**
+     * Creates new YANG Schema revision source identifier.
+     *
+     * @param moduleName
+     *            Name of schema
+     * @param revision
+     *            Revision of source in format YYYY-mm-dd
+     */
+    public static RevisionSourceIdentifier create(final String moduleName, final String revision) {
+        return new RevisionSourceIdentifier(moduleName, revision);
+    }
+
+    /**
+     *
+     * Creates new YANG Schema revision source identifier for sources without
+     * revision. {@link SourceIdentifier#NOT_PRESENT_FORMATTED_REVISION} as
+     * default revision.
+     *
+     * @param moduleName
+     *            Name of schema
+     */
+    public static RevisionSourceIdentifier create(final String moduleName) {
+        return new RevisionSourceIdentifier(moduleName);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Objects.hashCode(getName());
+        result = prime * result + Objects.hashCode(getRevision());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof RevisionSourceIdentifier)) {
+            return false;
+        }
+        final RevisionSourceIdentifier other = (RevisionSourceIdentifier) obj;
+        return Objects.equals(getName(), other.getName()) && Objects.equals(getRevision(), other.getRevision());
+    }
+
+    @Override
+    public String toString() {
+        return "RevisionSourceIdentifier [name=" + getName() + "@" + getRevision() + "]";
+    }
+}
index 9b338a742b601ac66db2bcd95e006ab7c9665322..ddf9c53770ed546811c330c3c67ea5b4ef3730c8 100644 (file)
@@ -16,39 +16,78 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 /**
- * An asynchronous factory for building {@link SchemaContext} instances
- * based on a specification of what {@link SourceIdentifier}s are required
- * and dynamic recursive resolution.
+ * An asynchronous factory for building {@link SchemaContext} instances based on
+ * a specification of what {@link SourceIdentifier}s are required and dynamic
+ * recursive resolution.
  */
 @Beta
 public interface SchemaContextFactory {
     /**
-     * Create a new schema context containing specified sources, pulling in
-     * any dependencies they may have.
+     * Create a new schema context containing specified sources, pulling in any
+     * dependencies they may have.
      *
-     * @param requiredSources a collection of sources which are required to
-     *                        be present
-     * @return A checked future, which will produce a schema context, or
-     *         fail with an explanation why the creation of the schema context
+     * @param requiredSources
+     *            a collection of sources which are required to be present
+     * @return A checked future, which will produce a schema context, or fail
+     *         with an explanation why the creation of the schema context
      *         failed.
      */
     default CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
             @Nonnull Collection<SourceIdentifier> requiredSources) {
-        return createSchemaContext(requiredSources, t -> true);
+        return createSchemaContext(requiredSources, StatementParserMode.DEFAULT_MODE, t -> true);
     }
 
     /**
-     * Create a new schema context containing specified sources, pulling in
-     * any dependencies they may have.
+     * Create a new schema context containing specified sources, pulling in any
+     * dependencies they may have.
      *
-     * @param requiredSources a collection of sources which are required to
-     *                        be present
-     * @param isFeatureSupported a predicate based on which all if-feature statements in the parsed yang
-     *                          models are resolved
-     * @return A checked future, which will produce a schema context, or
-     *         fail with an explanation why the creation of the schema context
+     * @param requiredSources
+     *            a collection of sources which are required to be present
+     * @param statementParserMode
+     *            mode of statement parser
+     * @return A checked future, which will produce a schema context, or fail
+     *         with an explanation why the creation of the schema context
+     *         failed.
+     */
+    default CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
+            Collection<SourceIdentifier> requiredSources, StatementParserMode statementParserMode) {
+        return createSchemaContext(requiredSources, statementParserMode, t -> true);
+    }
+
+    /**
+     * Create a new schema context containing specified sources, pulling in any
+     * dependencies they may have.
+     *
+     * @param requiredSources
+     *            a collection of sources which are required to be present
+     * @param isFeatureSupported
+     *            a predicate based on which all if-feature statements in the
+     *            parsed yang models are resolved
+     * @return A checked future, which will produce a schema context, or fail
+     *         with an explanation why the creation of the schema context
+     *         failed.
+     */
+    default CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
+            @Nonnull Collection<SourceIdentifier> requiredSources, Predicate<QName> isFeatureSupported) {
+        return createSchemaContext(requiredSources, StatementParserMode.DEFAULT_MODE, isFeatureSupported);
+    }
+
+    /**
+     * Create a new schema context containing specified sources, pulling in any
+     * dependencies they may have.
+     *
+     * @param requiredSources
+     *            a collection of sources which are required to be present
+     * @param statementParserMode
+     *            mode of statement parser
+     * @param isFeatureSupported
+     *            a predicate based on which all if-feature statements in the
+     *            parsed yang models are resolved
+     * @return A checked future, which will produce a schema context, or fail
+     *         with an explanation why the creation of the schema context
      *         failed.
      */
     CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
-            @Nonnull Collection<SourceIdentifier> requiredSources, Predicate<QName> isFeatureSupported);
+            Collection<SourceIdentifier> requiredSources, StatementParserMode statementParserMode,
+            Predicate<QName> isFeatureSupported);
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SemVerSourceIdentifier.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SemVerSourceIdentifier.java
new file mode 100644 (file)
index 0000000..88f5168
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016 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/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import java.util.Objects;
+import org.opendaylight.yangtools.concepts.SemVer;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+/**
+ * YANG Schema source identifier with specified semantic version
+ *
+ * Simple transfer object represents identifier of source for YANG schema
+ * (module or submodule), which consists of
+ * <ul>
+ * <li>YANG schema name {@link #getName()}
+ * <li>Semantic version of yang schema {@link #getSemanticVersion()}
+ * <li>(Optional) Module revision ({link {@link #getRevision()}
+ * </ul>
+ *
+ * Source identifier is designated to be carry only necessary information to
+ * look-up YANG model source and to be used by various SchemaSourceProviders.
+ *
+ * <b>Note:</b>On source retrieval layer it is impossible to distinguish between
+ * YANG module and/or submodule unless source is present.
+ *
+ * <p>
+ * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2
+ * and http://tools.ietf.org/html/rfc6022#section-3.1 ).
+ */
+@Beta
+public final class SemVerSourceIdentifier extends SourceIdentifier {
+    private static final long serialVersionUID = 1L;
+    private final SemVer semVer;
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Optional of source revision in format YYYY-mm-dd. If not
+     *            present, default value will be used.
+     * @param semVer
+     *            semantic version of source
+     */
+    SemVerSourceIdentifier(final String name, final Optional<String> formattedRevision, final SemVer semVer) {
+        this(name, formattedRevision.or(NOT_PRESENT_FORMATTED_REVISION), semVer);
+    }
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param name
+     *            Name of schema
+     * @param semVer
+     *            semantic version of source
+     */
+    SemVerSourceIdentifier(final String name, final SemVer semVer) {
+        this(name, Optional.absent(), semVer);
+    }
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Revision of source in format YYYY-mm-dd
+     * @param semVer
+     *            semantic version of source
+     */
+    SemVerSourceIdentifier(final String name, final String formattedRevision, final SemVer semVer) {
+        super(name, formattedRevision);
+        this.semVer = semVer == null ? Module.DEFAULT_SEMANTIC_VERSION : semVer;
+    }
+
+    /**
+     * Returns semantic version of source or
+     * {@link Module#DEFAULT_SEMANTIC_VERSION} if semantic version was not
+     * supplied.
+     *
+     * @return revision of source or {@link Module#DEFAULT_SEMANTIC_VERSION} if
+     *         revision was not supplied.
+     */
+    public SemVer getSemanticVersion() {
+        return semVer;
+    }
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param moduleName
+     *            Name of schema
+     * @param semVer
+     *            semantic version of source
+     */
+    public static SemVerSourceIdentifier create(final String moduleName, final SemVer semVer) {
+        return new SemVerSourceIdentifier(moduleName, semVer);
+    }
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param moduleName
+     *            Name of schema
+     * @param revision
+     *            Revision of source in format YYYY-mm-dd
+     * @param semVer
+     *            semantic version of source
+     */
+    public static SemVerSourceIdentifier create(final String moduleName, final String revision,
+            final SemVer semVer) {
+        return new SemVerSourceIdentifier(moduleName, revision, semVer);
+    }
+
+    /**
+     * Creates new YANG Schema semVer source identifier.
+     *
+     * @param moduleName
+     *            Name of schema
+     * @param revision
+     *            Optional of source revision in format YYYY-mm-dd. If not
+     *            present, default value will be used.
+     * @param semVer
+     *            semantic version of source
+     */
+    public static SemVerSourceIdentifier create(final String moduleName,
+            final Optional<String> revision, final SemVer semVer) {
+        return new SemVerSourceIdentifier(moduleName, revision, semVer);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Objects.hashCode(getName());
+        result = prime * result + Objects.hashCode(semVer);
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SemVerSourceIdentifier)) {
+            return false;
+        }
+        final SemVerSourceIdentifier other = (SemVerSourceIdentifier) obj;
+        return Objects.equals(getName(), other.getName()) && Objects.equals(semVer, other.semVer);
+    }
+
+    @Override
+    public String toString() {
+        return "SemVerSourceIdentifier [name=" + getName() + "(" + semVer + ")" + "@" + getRevision() + "]";
+    }
+}
index fba3630573038bbcc8d3c789e7c0b030372e3704..48ce2a7c0b2c4aa950214af5644e2e3b0da44244 100644 (file)
@@ -10,7 +10,8 @@ package org.opendaylight.yangtools.yang.model.repo.api;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import java.util.Objects;
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
 import java.util.regex.Pattern;
 import org.opendaylight.yangtools.concepts.Identifier;
 import org.opendaylight.yangtools.concepts.Immutable;
@@ -19,30 +20,19 @@ import org.opendaylight.yangtools.objcache.ObjectCacheFactory;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
 
 /**
- * YANG Schema source identifier
+ * Base class of YANG Schema source identifiers.
  *
- * Simple transfer object represents identifier of source for YANG schema (module or submodule),
- * which consists of
- * <ul>
- * <li>YANG schema name ({@link #getName()}
- * <li>Module revision (optional) ({link {@link #getRevision()})
- * </ul>
+ * Source identifiers are designated to be carry only necessary information to
+ * look-up YANG model source and to be used by various SchemaSourceProviders.
  *
- * Source identifier is designated to be carry only necessary information
- * to look-up YANG model source and to be used by various SchemaSourceProviders.
- *
- * <b>Note:</b>On source retrieval layer it is impossible to distinguish
- * between YANG module and/or submodule unless source is present.
- *
- * <p>
- * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2 and
- * http://tools.ietf.org/html/rfc6022#section-3.1 ).
+ * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2
+ * and http://tools.ietf.org/html/rfc6022#section-3.1 ).
  */
 @Beta
-public final class SourceIdentifier implements Identifier, Immutable {
+public abstract class SourceIdentifier implements Identifier, Immutable {
     /**
-     * Default revision for sources without specified revision.
-     * Marks the source as oldest.
+     * Default revision for sources without specified revision. Marks the source
+     * as oldest.
      */
     public static final String NOT_PRESENT_FORMATTED_REVISION = "0000-00-00";
 
@@ -51,13 +41,15 @@ public final class SourceIdentifier implements Identifier, Immutable {
      * Simplified compiled revision pattern in format YYYY-mm-dd, which checks
      * only distribution of number elements.
      * <p>
-     * For checking if supplied string is real date, use {@link SimpleDateFormatUtil}
-     * instead.
+     * For checking if supplied string is real date, use
+     * {@link SimpleDateFormatUtil} instead.
      *
      */
     public static final Pattern REVISION_PATTERN = Pattern.compile("\\d\\d\\d\\d-\\d\\d-\\d\\d");
 
     private static final ObjectCache CACHE = ObjectCacheFactory.getObjectCache(SourceIdentifier.class);
+    private static final Interner<SourceIdentifier> INTERNER = Interners.newWeakInterner();
+
     private static final long serialVersionUID = 1L;
     private final String revision;
     private final String name;
@@ -65,21 +57,25 @@ public final class SourceIdentifier implements Identifier, Immutable {
     /**
      *
      * Creates new YANG Schema source identifier for sources without revision.
-     * {@link SourceIdentifier#NOT_PRESENT_FORMATTED_REVISION} as default revision.
+     * {@link SourceIdentifier#NOT_PRESENT_FORMATTED_REVISION} as default
+     * revision.
      *
-     * @param name Name of schema
+     * @param name
+     *            Name of schema
      */
-    public SourceIdentifier(final String name) {
+    SourceIdentifier(final String name) {
         this(name, NOT_PRESENT_FORMATTED_REVISION);
     }
 
     /**
      * Creates new YANG Schema source identifier.
      *
-     * @param name Name of schema
-     * @param formattedRevision Revision of source in format YYYY-mm-dd
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Revision of source in format YYYY-mm-dd
      */
-    public SourceIdentifier(final String name, final String formattedRevision) {
+    SourceIdentifier(final String name, final String formattedRevision) {
         this.name = Preconditions.checkNotNull(name);
         this.revision = Preconditions.checkNotNull(formattedRevision);
     }
@@ -88,10 +84,13 @@ public final class SourceIdentifier implements Identifier, Immutable {
      *
      * Creates new YANG Schema source identifier.
      *
-     * @param name Name of schema
-     * @param formattedRevision Revision of source in format YYYY-mm-dd. If not present, default value will be used.
+     * @param name
+     *            Name of schema
+     * @param formattedRevision
+     *            Revision of source in format YYYY-mm-dd. If not present,
+     *            default value will be used.
      */
-    public SourceIdentifier(final String name, final Optional<String> formattedRevision) {
+    SourceIdentifier(final String name, final Optional<String> formattedRevision) {
         this(name, formattedRevision.or(NOT_PRESENT_FORMATTED_REVISION));
     }
 
@@ -100,10 +99,20 @@ public final class SourceIdentifier implements Identifier, Immutable {
      *
      * @return A potentially shared reference, not guaranteed to be unique.
      */
+    @Deprecated
     public SourceIdentifier cachedReference() {
         return CACHE.getReference(this);
     }
 
+    /**
+     * Return an interned reference to a equivalent SemVerSourceIdentifier.
+     *
+     * @return Interned reference, or this object if it was interned.
+     */
+    public SourceIdentifier intern() {
+        return INTERNER.intern(this);
+    }
+
     /**
      * Returns model name
      *
@@ -122,41 +131,17 @@ public final class SourceIdentifier implements Identifier, Immutable {
         return revision;
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + Objects.hashCode(name);
-        result = prime * result + Objects.hashCode(revision);
-        return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        SourceIdentifier other = (SourceIdentifier) obj;
-        return Objects.equals(name, other.name) && Objects.equals(revision, other.revision);
-    }
-
+    @Deprecated
     public static SourceIdentifier create(final String moduleName, final Optional<String> revision) {
-        return new SourceIdentifier(moduleName, revision);
+        return new RevisionSourceIdentifier(moduleName, revision);
     }
 
     /**
      * Returns filename for this YANG module as specified in RFC 6020.
      *
-     * Returns filename in format
-     * <code>name ['@' revision] '.yang'</code>
+     * Returns filename in format <code>name ['@' revision] '.yang'</code>
      * <p>
-     * Where revision is  date in format YYYY-mm-dd.
+     * Where revision is date in format YYYY-mm-dd.
      * <p>
      *
      * @see <a href="http://tools.ietf.org/html/rfc6020#section-5.2">RFC6020</a>
@@ -167,22 +152,15 @@ public final class SourceIdentifier implements Identifier, Immutable {
         return toYangFileName(name, Optional.fromNullable(revision));
     }
 
-    @Override
-    public String toString() {
-        return "SourceIdentifier [name=" + name + "@" + revision + "]";
-    }
-
     /**
      * Returns filename for this YANG module as specified in RFC 6020.
      *
-     * Returns filename in format
-     * <code>moduleName ['@' revision] '.yang'</code>
+     * Returns filename in format <code>moduleName ['@' revision] '.yang'</code>
      *
      * Where Where revision-date is in format YYYY-mm-dd.
      *
      * <p>
-     * See
-     * http://tools.ietf.org/html/rfc6020#section-5.2
+     * See http://tools.ietf.org/html/rfc6020#section-5.2
      *
      * @return Filename for this source identifier.
      */
@@ -195,5 +173,4 @@ public final class SourceIdentifier implements Identifier, Immutable {
         filename.append(".yang");
         return filename.toString();
     }
-
 }
index 6a4b83a5ebd5e9976a248e6a75bc60e3004a1812..9915334bae0a9d84752d61efc7a56a90f531fb62 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.util;
 
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -290,7 +292,7 @@ public final class FilesystemSchemaSourceCache<T extends SchemaSourceRepresentat
             if (matcher.matches()) {
                 final String moduleName = matcher.group("moduleName");
                 final String revision = matcher.group("revision");
-                return Optional.of(new SourceIdentifier(moduleName, Optional.fromNullable(revision)));
+                return Optional.of(RevisionSourceIdentifier.create(moduleName, Optional.fromNullable(revision)));
             }
             return Optional.absent();
         }
index ea80590ce045cb5f0eda7079956678cf861a0b7d..0c4d48cb7ba71f18cd56c37b9d1029460475f115 100644 (file)
@@ -19,6 +19,8 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.base.Charsets;
 import com.google.common.base.Function;
 import com.google.common.base.MoreObjects;
@@ -144,7 +146,7 @@ public class FilesystemSchemaSourceCacheTest {
 
     @Test
     public void sourceIdToFileEmptyRevWithEmptyDir() {
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "");
         final File sourceIdToFile = FilesystemSchemaSourceCache.sourceIdToFile(sourceIdentifier, this.storageDir);
         final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(this.registry,
                 YangTextSchemaSource.class, sourceIdToFile);
@@ -161,7 +163,7 @@ public class FilesystemSchemaSourceCacheTest {
         final YangTextSchemaSource source = new TestingYangSource("test", "2013-12-12", content);
         cache.offer(source);
 
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "");
         final File sourceIdToFile = FilesystemSchemaSourceCache.sourceIdToFile(sourceIdentifier,
                 this.storageDir);
         Assert.assertNotNull(sourceIdToFile);
@@ -179,7 +181,7 @@ public class FilesystemSchemaSourceCacheTest {
         cache.offer(source);
         cache.offer(source2);
 
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "");
         final File sourceIdToFile = FilesystemSchemaSourceCache.sourceIdToFile(sourceIdentifier, this.storageDir);
         Assert.assertNotNull(sourceIdToFile);
         final List<File> storedFiles = Arrays.asList(this.storageDir.listFiles());
@@ -194,7 +196,7 @@ public class FilesystemSchemaSourceCacheTest {
         final String content = "content1";
         final YangTextSchemaSource source = new TestingYangSource("test", "2013-12-12", content);
         cache.offer(source);
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "2013-12-12");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "2013-12-12");
         final CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException> checked = cache
                 .getSource(sourceIdentifier);
         Assert.assertNotNull(checked);
@@ -211,7 +213,7 @@ public class FilesystemSchemaSourceCacheTest {
         final String content = "content1";
         final YangTextSchemaSource source = new TestingYangSource("test", "2013-12-12", content);
         cache.offer(source);
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test1", "2012-12-12");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test1", "2012-12-12");
         final CheckedFuture<? extends YangTextSchemaSource, SchemaSourceException> checked = cache
                 .getSource(sourceIdentifier);
         Assert.assertNotNull(checked);
@@ -227,7 +229,7 @@ public class FilesystemSchemaSourceCacheTest {
         private final String content;
 
         protected TestingYangSource(final String name, final String revision, final String content) {
-            super(new SourceIdentifier(name, Optional.fromNullable(revision)));
+            super(RevisionSourceIdentifier.create(name, Optional.fromNullable(revision)));
             this.content = content;
         }
 
index 2fa857512010799398688f8cbe2940613214ca75..14d5e2ffce831c74c28ffc9dce387516a9c36260 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.model.repo.util;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doReturn;
+
 import com.google.common.base.Charsets;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Optional;
@@ -24,6 +25,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
@@ -76,7 +78,7 @@ public class InMemorySchemaSourceCacheTest {
         final String content = "content";
         final YangTextSchemaSource source = new TestingYangSource("test", "2012-12-12", content);
         inMemorySchemaSourceCache.offer(source);
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "2012-12-12");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "2012-12-12");
         final CheckedFuture<? extends YangSchemaSourceRepresentation, SchemaSourceException> checkedSource = inMemorySchemaSourceCache
                 .getSource(sourceIdentifier);
         Assert.assertNotNull(checkedSource);
@@ -90,7 +92,7 @@ public class InMemorySchemaSourceCacheTest {
     public void inMemorySchemaSourceCacheNullGetSourcestest() throws Exception {
         final InMemorySchemaSourceCache<YangSchemaSourceRepresentation> inMemorySchemaSourceCache = InMemorySchemaSourceCache
                 .createSoftCache(this.registry, InMemorySchemaSourceCacheTest.representation);
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "2012-12-12");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "2012-12-12");
         final CheckedFuture<? extends YangSchemaSourceRepresentation, SchemaSourceException> checkedSource = inMemorySchemaSourceCache
                 .getSource(sourceIdentifier);
         Assert.assertNotNull(checkedSource);
@@ -112,7 +114,7 @@ public class InMemorySchemaSourceCacheTest {
         inMemorySchemaSourceCache.offer(source);
         inMemorySchemaSourceCache2.offer(source);
 
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("test", "2012-12-12");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("test", "2012-12-12");
         final CheckedFuture<? extends YangSchemaSourceRepresentation, SchemaSourceException> checkedSource = inMemorySchemaSourceCache
                 .getSource(sourceIdentifier);
         final CheckedFuture<? extends SchemaSourceRepresentation, SchemaSourceException> checkedSource2 = inMemorySchemaSourceCache2
@@ -130,7 +132,7 @@ public class InMemorySchemaSourceCacheTest {
         private final String content;
 
         protected TestingYangSource(final String name, final String revision, final String content) {
-            super(new SourceIdentifier(name, Optional.fromNullable(revision)));
+            super(RevisionSourceIdentifier.create(name, Optional.fromNullable(revision)));
             this.content = content;
         }
 
index 20a43df62d2966c811229dd637ccfd23235a10a1..461dcf6c7376ad0d7991a73fe86df14370c1b019 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.util;
 
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.util.concurrent.AsyncFunction;
 import com.google.common.util.concurrent.CheckedFuture;
 import java.util.Arrays;
@@ -59,7 +61,7 @@ public class SchemaSourceTransformerTest {
     public void schemaSourceTransformerGetSourceTest() throws Exception {
         final Provider p = new Provider();
         final Registrator reg = new Registrator(p, SchemaSourceTransformerTest.SRC_CLASS, PotentialSchemaSource.Costs.IMMEDIATE);
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("source");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("source");
         reg.register(sourceIdentifier);
         this.schema = new SchemaSourceTransformer<>(p,
                 SchemaSourceTransformerTest.SRC_CLASS, this.consumer, SchemaSourceTransformerTest.DST_CLASS,
@@ -73,7 +75,7 @@ public class SchemaSourceTransformerTest {
 
     @Test
     public void schemaSourceRegAndUnregSchemaSourceTest() throws Exception {
-        final SourceIdentifier sourceIdentifier = new SourceIdentifier("source");
+        final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("source");
         final Foo<YangSchemaSourceRepresentation> foo = new Foo<>(sourceIdentifier,
                 SchemaSourceTransformerTest.SRC_CLASS,
                 PotentialSchemaSource.Costs.COMPUTATION);
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() + "]";
         }
     }
 }
index d24e8ae116d6efb9b76a5ed5b8cf22ae2d917b85..bc339f7f54932488dc77211a9372424a1376a370 100644 (file)
@@ -8,22 +8,19 @@
 package org.opendaylight.yangtools.yang.parser.repo;
 
 import com.google.common.base.MoreObjects;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import org.opendaylight.yangtools.concepts.SemVer;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
@@ -40,45 +37,13 @@ import org.slf4j.LoggerFactory;
  *        That information will allow us to track "damage" to dependency resolution
  *        as new models are added to a schema context.
  */
-final class DependencyResolver {
+abstract class DependencyResolver {
     private static final Logger LOG = LoggerFactory.getLogger(DependencyResolver.class);
     private final Collection<SourceIdentifier> resolvedSources;
     private final Collection<SourceIdentifier> unresolvedSources;
     private final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports;
 
-    public DependencyResolver(final Collection<SourceIdentifier> resolvedSources,
-            final Collection<SourceIdentifier> unresolvedSources, final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
-        this.resolvedSources = Preconditions.checkNotNull(resolvedSources);
-        this.unresolvedSources = Preconditions.checkNotNull(unresolvedSources);
-        this.unsatisfiedImports = Preconditions.checkNotNull(unsatisfiedImports);
-    }
-
-    private static SourceIdentifier findWildcard(final Iterable<SourceIdentifier> haystack, final String needle) {
-        for (final SourceIdentifier r : haystack) {
-            if (r.getName().equals(needle)) {
-                return r;
-            }
-        }
-
-        return null;
-    }
-
-    private static boolean isKnown(final Collection<SourceIdentifier> haystack, final ModuleImport mi) {
-        final String rev = mi.getRevision() != null ? QName.formattedRevision(mi.getRevision()) : null;
-        final SourceIdentifier msi = SourceIdentifier.create(mi.getModuleName(), Optional.fromNullable(rev));
-
-        // Quick lookup
-        if (haystack.contains(msi)) {
-            return true;
-        }
-
-        // Slow revision-less walk
-        return rev == null && findWildcard(haystack, mi.getModuleName()) != null;
-    }
-
-
-
-    public static DependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
+    protected DependencyResolver(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
         final Collection<SourceIdentifier> resolved = new ArrayList<>(depInfo.size());
         final Collection<SourceIdentifier> pending = new ArrayList<>(depInfo.keySet());
         final Map<SourceIdentifier, BelongsToDependency> submodules = Maps.newHashMap();
@@ -130,23 +95,23 @@ final class DependencyResolver {
             }
         }
 
-        if (!pending.isEmpty()) {
-            final Multimap<SourceIdentifier, ModuleImport> imports = ArrayListMultimap.create();
-            for (final SourceIdentifier id : pending) {
-                final YangModelDependencyInfo dep = depInfo.get(id);
-                for (final ModuleImport mi : dep.getDependencies()) {
-                    if (!isKnown(pending, mi) && !isKnown(resolved, mi)) {
-                        imports.put(id, mi);
-                    }
+        final Multimap<SourceIdentifier, ModuleImport> imports = ArrayListMultimap.create();
+        for (final SourceIdentifier id : pending) {
+            final YangModelDependencyInfo dep = depInfo.get(id);
+            for (final ModuleImport mi : dep.getDependencies()) {
+                if (!isKnown(pending, mi) && !isKnown(resolved, mi)) {
+                    imports.put(id, mi);
                 }
             }
-
-            return new DependencyResolver(resolved, pending, imports);
-        } else {
-            return new DependencyResolver(resolved, Collections.emptyList(), ImmutableMultimap.of());
         }
+
+        this.resolvedSources = ImmutableList.copyOf(resolved);
+        this.unresolvedSources = ImmutableList.copyOf(pending);
+        this.unsatisfiedImports = ImmutableMultimap.copyOf(imports);
     }
 
+    abstract protected boolean isKnown(final Collection<SourceIdentifier> haystack, final ModuleImport mi);
+
     /**
      * Collection of sources which have been resolved.
      *
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/RevisionDependencyResolver.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/RevisionDependencyResolver.java
new file mode 100644 (file)
index 0000000..7239ff5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 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/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+
+final class RevisionDependencyResolver extends DependencyResolver {
+
+    protected RevisionDependencyResolver(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
+        super(depInfo);
+    }
+
+    protected static SourceIdentifier findWildcard(final Iterable<SourceIdentifier> haystack, final String needle) {
+        for (final SourceIdentifier r : haystack) {
+            if (needle.equals(r.getName())) {
+                return r;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    protected boolean isKnown(final Collection<SourceIdentifier> haystack, final ModuleImport mi) {
+        final String rev = mi.getRevision() != null ? QName.formattedRevision(mi.getRevision()) : null;
+        final SourceIdentifier msi = SourceIdentifier.create(mi.getModuleName(), Optional.fromNullable(rev));
+
+        // Quick lookup
+        if (haystack.contains(msi)) {
+            return true;
+        }
+
+        // Slow revision-less walk
+        return rev == null && findWildcard(haystack, mi.getModuleName()) != null;
+    }
+
+    public static RevisionDependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
+        return new RevisionDependencyResolver(depInfo);
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SemVerDependencyResolver.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SemVerDependencyResolver.java
new file mode 100644 (file)
index 0000000..8567254
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 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/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.Map;
+import org.opendaylight.yangtools.concepts.SemVer;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+
+final class SemVerDependencyResolver extends DependencyResolver {
+
+    protected SemVerDependencyResolver(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
+        super(depInfo);
+    }
+
+    protected static SourceIdentifier findCompatibleVersion(final Iterable<SourceIdentifier> haystack, final ModuleImport mi) {
+        final String requestedModuleName = mi.getModuleName();
+        for (SourceIdentifier r : haystack) {
+            if (requestedModuleName.equals(r.getName())
+                    && isCompatible(((SemVerSourceIdentifier) r).getSemanticVersion(), mi.getSemanticVersion())) {
+                return r;
+            }
+        }
+
+        return null;
+    }
+
+    private static boolean isCompatible(final SemVer moduleSemVer, final SemVer importSemVer) {
+        return moduleSemVer.getMajor() == importSemVer.getMajor() && moduleSemVer.compareTo(importSemVer) >= 0;
+    }
+
+    @Override
+    protected boolean isKnown(final Collection<SourceIdentifier> haystack, final ModuleImport mi) {
+        final String rev = mi.getRevision() != null ? QName.formattedRevision(mi.getRevision()) : null;
+        final SemVerSourceIdentifier msi = SemVerSourceIdentifier.create(mi.getModuleName(), Optional.fromNullable(rev), mi.getSemanticVersion());
+
+        // Quick lookup
+        if (haystack.contains(msi)) {
+            return true;
+        }
+
+        // Slow revision-less walk
+        return findCompatibleVersion(haystack, mi) != null;
+    }
+
+    public static SemVerDependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
+        return new SemVerDependencyResolver(depInfo);
+    }
+}
\ No newline at end of file
index 1594fd4212704836a7207008bfb619f9cafd67b6..7b40342003c575eca5692f0f88d4ca6ad827a441 100644 (file)
@@ -39,6 +39,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
@@ -60,6 +61,7 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
         }
     };
     private final Cache<Collection<SourceIdentifier>, SchemaContext> cache = CacheBuilder.newBuilder().weakValues().build();
+    private final Cache<Collection<SourceIdentifier>, SchemaContext> semVerCache = CacheBuilder.newBuilder().weakValues().build();
     private final SharedSchemaRepository repository;
     // FIXME: ignored right now
     private final SchemaSourceFilter filter;
@@ -72,7 +74,14 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
 
     @Override
     public CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
-            final Collection<SourceIdentifier> requiredSources, java.util.function.Predicate<QName> isFeatureSupported) {
+            final Collection<SourceIdentifier> requiredSources, final StatementParserMode statementParserMode,
+            final java.util.function.Predicate<QName> isFeatureSupported) {
+        return createSchemaContext(requiredSources,
+                statementParserMode == StatementParserMode.SEMVER_MODE ? this.semVerCache : this.cache,
+                new AssembleSources(isFeatureSupported, statementParserMode));
+    }
+
+    private CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(final Collection<SourceIdentifier> requiredSources, final Cache<Collection<SourceIdentifier>, SchemaContext> cache, final AsyncFunction<List<ASTSchemaSource>, SchemaContext> assembleSources) {
         // Make sources unique
         final List<SourceIdentifier> uniqueSourceIdentifiers = deDuplicateSources(requiredSources);
 
@@ -91,7 +100,6 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
         sf = Futures.transform(sf, new SourceIdMismatchDetector(uniqueSourceIdentifiers));
 
         // Assemble sources into a schema context
-        final AssembleSources assembleSources = new AssembleSources(isFeatureSupported);
         final ListenableFuture<SchemaContext> cf = Futures.transform(sf, assembleSources);
 
         // Populate cache when successful
@@ -166,22 +174,33 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
     private static final class AssembleSources implements AsyncFunction<List<ASTSchemaSource>, SchemaContext> {
 
         private final java.util.function.Predicate<QName> isFeatureSupported;
+        private final StatementParserMode statementParserMode;
+        private final Function<ASTSchemaSource, SourceIdentifier> getIdentifier;
 
-        private AssembleSources(final java.util.function.Predicate<QName> isFeatureSupported) {
+        private AssembleSources(final java.util.function.Predicate<QName> isFeatureSupported,
+                final StatementParserMode statementParserMode) {
             this.isFeatureSupported = Preconditions.checkNotNull(isFeatureSupported);
+            this.statementParserMode = Preconditions.checkNotNull(statementParserMode);
+            switch (statementParserMode) {
+            case SEMVER_MODE:
+                this.getIdentifier = ASTSchemaSource.GET_SEMVER_IDENTIFIER;
+                break;
+            default:
+                this.getIdentifier = ASTSchemaSource.GET_IDENTIFIER;
+            }
         }
 
         @Override
-        public ListenableFuture<SchemaContext> apply(List<ASTSchemaSource> sources) throws SchemaResolutionException,
+        public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException,
                 SourceException, ReactorException {
-            final Map<SourceIdentifier, ASTSchemaSource> srcs =
-                    Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
+            final Map<SourceIdentifier, ASTSchemaSource> srcs = Maps.uniqueIndex(sources, getIdentifier);
             final Map<SourceIdentifier, YangModelDependencyInfo> deps =
                     Maps.transformValues(srcs, ASTSchemaSource.GET_DEPINFO);
 
             LOG.debug("Resolving dependency reactor {}", deps);
 
-            final DependencyResolver res = DependencyResolver.create(deps);
+            final DependencyResolver res = this.statementParserMode == StatementParserMode.SEMVER_MODE ? SemVerDependencyResolver
+                    .create(deps) : RevisionDependencyResolver.create(deps);
             if (!res.getUnresolvedSources().isEmpty()) {
                 LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
                 throw new SchemaResolutionException("Failed to resolve required models",
@@ -190,7 +209,7 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
 
             final Map<SourceIdentifier, ParserRuleContext> asts = Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
             final CrossSourceStatementReactor.BuildAction reactor =
-                    YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
+                    YangInferencePipeline.RFC6020_REACTOR.newBuild(statementParserMode, isFeatureSupported);
 
             for (final Entry<SourceIdentifier, ParserRuleContext> e : asts.entrySet()) {
                 final ParserRuleContext parserRuleCtx = e.getValue();
@@ -200,7 +219,7 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
                 reactor.addSource(new YangStatementSourceImpl(e.getKey(), (StatementContext) parserRuleCtx));
             }
 
-            SchemaContext schemaContext = reactor.buildEffective();
+            final SchemaContext schemaContext = reactor.buildEffective();
 
             return Futures.immediateCheckedFuture(schemaContext);
         }
index 3a79452e7ad7ce67bd0b79071362c117283b360f..a2bbcd84015e50646c24a4f3cb4087590a64e2de 100644 (file)
@@ -8,6 +8,9 @@
 package org.opendaylight.yangtools.yang.parser.repo;
 
 import static com.google.common.base.Preconditions.checkArgument;
+
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -34,6 +37,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
@@ -159,7 +163,7 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
     public YangTextSchemaSourceRegistration registerSource(@Nonnull final URL url) throws SchemaSourceException, IOException, YangSyntaxErrorException {
         checkArgument(url != null, "Supplied URL must not be null");
 
-        final SourceIdentifier guessedId = new SourceIdentifier(url.getFile(), Optional.absent());
+        final SourceIdentifier guessedId = RevisionSourceIdentifier.create(url.getFile(), Optional.absent());
         return registerSource(new YangTextSchemaSource(guessedId) {
             @Override
             public InputStream openStream() throws IOException {
@@ -179,6 +183,18 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
      *         new schema context was successfully built.
      */
     public Optional<SchemaContext> getSchemaContext() {
+        return getSchemaContext(StatementParserMode.DEFAULT_MODE);
+    }
+
+    /**
+     * Try to parse all currently available yang files and build new schema context
+     * in dependence on specified parsing mode.
+     *
+     * @param statementParserMode mode of statement parser
+     * @return new schema context iif there is at least 1 yang file registered and
+     *         new schema context was successfully built.
+     */
+    public Optional<SchemaContext> getSchemaContext(StatementParserMode statementParserMode) {
         final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
         Optional<SchemaContext> sc;
         Object v;
@@ -201,7 +217,7 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
             } while (v != version);
 
             while (true) {
-                final CheckedFuture<SchemaContext, SchemaResolutionException> f = factory.createSchemaContext(sources);
+                final CheckedFuture<SchemaContext, SchemaResolutionException> f = factory.createSchemaContext(sources, statementParserMode);
                 try {
                     sc = Optional.of(f.checkedGet());
                     break;
index 593899da89495e7306efb31ba120cfc0a1a66a49..c797294da592fc9268aa6e1ad0b9867899c9c7e0 100644 (file)
@@ -78,6 +78,7 @@ public final class Utils {
     private static final CharMatcher QUESTION_MARK_MATCHER = CharMatcher.is('?');
     private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults();
     private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
+    private static final Splitter COLON_SPLITTER = Splitter.on(":").omitEmptyStrings().trimResults();
     private static final Pattern PATH_ABS = Pattern.compile("/[^/].*");
     private static final Pattern BETWEEN_CURLY_BRACES_PATTERN = Pattern.compile("\\{(.+?)\\}");
     private static final Set<String> JAVA_UNICODE_BLOCKS = ImmutableSet.<String>builder()
@@ -385,6 +386,14 @@ public final class Utils {
         return identifier;
     }
 
+    public static String trimPrefix(final String identifier) {
+        List<String> namesParts = COLON_SPLITTER.splitToList(identifier);
+        if (namesParts.size() == 2) {
+            return namesParts.get(1);
+        }
+        return identifier;
+    }
+
     /**
      *
      * Based on identifier read from source and collections of relevant prefixes and statement definitions mappings
index ab57ab74f9b57a4ae99376eab334885a65bbae77..ed914e2f132623bc5c5df9ff8bf807c3a2c4dd8f 100644 (file)
@@ -12,8 +12,11 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import javax.annotation.Nonnull;
 import org.antlr.v4.runtime.ParserRuleContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
 
@@ -36,6 +39,13 @@ public final class ASTSchemaSource implements SchemaSourceRepresentation {
             return input.getIdentifier();
         }
     };
+    public static final Function<ASTSchemaSource, SourceIdentifier> GET_SEMVER_IDENTIFIER = new Function<ASTSchemaSource, SourceIdentifier>() {
+        @Override
+        public SemVerSourceIdentifier apply(@Nonnull final ASTSchemaSource input) {
+            Preconditions.checkNotNull(input);
+            return input.getSemVerIdentifier();
+        }
+    };
     public static final Function<ASTSchemaSource, YangModelDependencyInfo> GET_DEPINFO = new Function<ASTSchemaSource, YangModelDependencyInfo>() {
         @Override
         public YangModelDependencyInfo apply(@Nonnull final ASTSchemaSource input) {
@@ -54,12 +64,14 @@ public final class ASTSchemaSource implements SchemaSourceRepresentation {
     private final YangModelDependencyInfo depInfo;
     private final ParserRuleContext tree;
     private final SourceIdentifier id;
+    private final SemVerSourceIdentifier semVerId;
     private final String text;
 
-    private ASTSchemaSource(@Nonnull final SourceIdentifier id, @Nonnull final ParserRuleContext tree, @Nonnull final YangModelDependencyInfo depInfo, final String text) {
+    private ASTSchemaSource(@Nonnull final SourceIdentifier id, @Nonnull final SemVerSourceIdentifier semVerId, @Nonnull final ParserRuleContext tree, @Nonnull final YangModelDependencyInfo depInfo, final String text) {
         this.depInfo = Preconditions.checkNotNull(depInfo);
         this.tree = Preconditions.checkNotNull(tree);
         this.id = Preconditions.checkNotNull(id);
+        this.semVerId = Preconditions.checkNotNull(semVerId);
         this.text = text;
     }
 
@@ -75,14 +87,22 @@ public final class ASTSchemaSource implements SchemaSourceRepresentation {
     public static ASTSchemaSource create(@Nonnull final String name, @Nonnull final ParserRuleContext tree) throws YangSyntaxErrorException {
         final YangModelDependencyInfo depInfo = YangModelDependencyInfo.fromAST(name, tree);
         final SourceIdentifier id = getSourceId(depInfo);
-        return new ASTSchemaSource(id, tree, depInfo, null);
+        final SemVerSourceIdentifier semVerId = getSemVerSourceId(depInfo);
+        return new ASTSchemaSource(id, semVerId, tree, depInfo, null);
     }
 
     private static SourceIdentifier getSourceId(final YangModelDependencyInfo depInfo) {
         final String name = depInfo.getName();
         return depInfo.getFormattedRevision() == null
-                ? new SourceIdentifier(name)
-                : new SourceIdentifier(name, depInfo.getFormattedRevision());
+                ? RevisionSourceIdentifier.create(name)
+                : RevisionSourceIdentifier.create(name, depInfo.getFormattedRevision());
+    }
+
+    private static SemVerSourceIdentifier getSemVerSourceId(final YangModelDependencyInfo depInfo) {
+        return depInfo.getFormattedRevision() == null ? SemVerSourceIdentifier.create(depInfo.getName(), depInfo
+                .getSemanticVersion().or(Module.DEFAULT_SEMANTIC_VERSION)) : SemVerSourceIdentifier.create(
+                depInfo.getName(), depInfo.getFormattedRevision(),
+                depInfo.getSemanticVersion().or(Module.DEFAULT_SEMANTIC_VERSION));
     }
 
     /**
@@ -101,15 +121,49 @@ public final class ASTSchemaSource implements SchemaSourceRepresentation {
     public static ASTSchemaSource create(@Nonnull final String name, @Nonnull final ParserRuleContext tree, final String text) throws YangSyntaxErrorException {
         final YangModelDependencyInfo depInfo = YangModelDependencyInfo.fromAST(name, tree);
         final SourceIdentifier id = getSourceId(depInfo);
-        return new ASTSchemaSource(id, tree, depInfo, text);
+        final SemVerSourceIdentifier semVerId = getSemVerSourceId(depInfo);
+        return new ASTSchemaSource(id, semVerId, tree, depInfo, text);
     }
 
+    /**
+     * Create a new instance of AST representation for a abstract syntax tree,
+     * performing minimal semantic analysis to acquire dependency information.
+     *
+     * @param identifier
+     *            SourceIdentifier of yang schema source.
+     * @param tree
+     *            ANTLR abstract syntax tree
+     * @param text
+     *            YANG text source
+     * @return A new representation instance.
+     * @throws YangSyntaxErrorException
+     *             if we fail to extract dependency information.
+     *
+     */
+    public static ASTSchemaSource create(@Nonnull final SourceIdentifier identifier,
+            @Nonnull final ParserRuleContext tree, final String text) throws YangSyntaxErrorException {
+        final YangModelDependencyInfo depInfo = YangModelDependencyInfo.fromAST(identifier.getName(), tree);
+        final SourceIdentifier id = getSourceId(depInfo);
+
+        final SemVerSourceIdentifier semVerId;
+        if (identifier instanceof SemVerSourceIdentifier && !depInfo.getSemanticVersion().isPresent()) {
+            semVerId = (SemVerSourceIdentifier) identifier;
+        } else {
+            semVerId = getSemVerSourceId(depInfo);
+        }
+
+        return new ASTSchemaSource(id, semVerId, tree, depInfo, text);
+    }
 
     @Override
     public SourceIdentifier getIdentifier() {
         return id;
     }
 
+    public SemVerSourceIdentifier getSemVerIdentifier() {
+        return semVerId;
+    }
+
     @Override
     public Class<? extends SchemaSourceRepresentation> getType() {
         return ASTSchemaSource.class;
index aa1b73e5c915af44d91aec21dee72b91873f00bd..aed627fd54aa0cadaa89535e8f14da77d4c6a9f1 100644 (file)
@@ -8,20 +8,20 @@
 
 package org.opendaylight.yangtools.yang.parser.util;
 
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Charsets;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import java.io.IOException;
 import java.io.InputStream;
+import org.antlr.v4.runtime.ParserRuleContext;
 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
 import org.opendaylight.yangtools.yang.model.repo.util.SchemaSourceTransformer;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +44,7 @@ public final class TextToASTTransformer extends SchemaSourceTransformer<YangText
                 // Backwards compatibility
                 final String text = input.asCharSource(Charsets.UTF_8).read();
 
-                return Futures.immediateCheckedFuture(ASTSchemaSource.create(input.getIdentifier().getName(), ctx, text));
+                return Futures.immediateCheckedFuture(ASTSchemaSource.create(input.getIdentifier(), ctx, text));
             }
         }
     }
index b18b31e7fb48b277933f6a1ee7d145af0879a6b0..b85d2d4cb3f4f582a743cabb7dfb45953bcd19a8 100644 (file)
@@ -9,6 +9,9 @@
 package org.opendaylight.yangtools.yang.parser.repo;
 
 import static org.junit.Assert.assertEquals;
+
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.base.Optional;
 import java.util.HashMap;
 import java.util.Map;
@@ -27,7 +30,7 @@ public class DependencyResolverTest {
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/no-revision/imported@2012-12-12.yang")));
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/no-revision/top@2012-10-10.yang")));
 
-        final DependencyResolver resolved = DependencyResolver.create(map);
+        final DependencyResolver resolved = RevisionDependencyResolver.create(map);
 
         assertEquals(0, resolved.getUnresolvedSources().size());
         assertEquals(0, resolved.getUnsatisfiedImports().size());
@@ -42,7 +45,7 @@ public class DependencyResolverTest {
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/bar.yang")));
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/baz.yang")));
 
-        final DependencyResolver resolved = DependencyResolver.create(map);
+        final DependencyResolver resolved = RevisionDependencyResolver.create(map);
 
         assertEquals(2, resolved.getResolvedSources().size());
         assertEquals(1, resolved.getUnresolvedSources().size());
@@ -58,7 +61,7 @@ public class DependencyResolverTest {
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/bar.yang")));
         addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/baz.yang")));
 
-        final DependencyResolver resolved = DependencyResolver.create(map);
+        final DependencyResolver resolved = RevisionDependencyResolver.create(map);
 
         assertEquals(4, resolved.getResolvedSources().size());
         assertEquals(0, resolved.getUnresolvedSources().size());
@@ -71,6 +74,6 @@ public class DependencyResolverTest {
 
     private static SourceIdentifier getSourceId(final YangModelDependencyInfo depInfo) {
         final String name = depInfo.getName();
-        return new SourceIdentifier(name, Optional.fromNullable(depInfo.getFormattedRevision()));
+        return RevisionSourceIdentifier.create(name, Optional.fromNullable(depInfo.getFormattedRevision()));
     }
 }
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SemVerSharedSchemaRepositoryTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SemVerSharedSchemaRepositoryTest.java
new file mode 100644 (file)
index 0000000..7b780ab
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 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/epl-v10.html
+ */
+
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
+import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+
+public class SemVerSharedSchemaRepositoryTest {
+
+    @Test
+    public void testSemVerSharedSchemaRepository() throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository(
+                "sem-ver-shared-schema-repo-test");
+
+        final SettableSchemaProvider<ASTSchemaSource> bar = getImmediateYangSourceProviderFromResource("/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang");
+        bar.register(sharedSchemaRepository);
+        bar.setResult();
+        final SettableSchemaProvider<ASTSchemaSource> foo = getImmediateYangSourceProviderFromResource("/semantic-version/semver-shared-schema-repository/foo.yang");
+        foo.register(sharedSchemaRepository);
+        foo.setResult();
+        final SettableSchemaProvider<ASTSchemaSource> semVer = getImmediateYangSourceProviderFromResource("/semantic-version/semver-shared-schema-repository/semantic-version.yang");
+        semVer.register(sharedSchemaRepository);
+        semVer.setResult();
+
+        final SchemaContextFactory fact = sharedSchemaRepository
+                .createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> inetAndTopologySchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(bar.getId(), foo.getId(), semVer.getId()), StatementParserMode.SEMVER_MODE);
+        assertTrue(inetAndTopologySchemaContextFuture.isDone());
+        assertSchemaContext(inetAndTopologySchemaContextFuture.checkedGet(), 3);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> barSchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(bar.getId(), semVer.getId()), StatementParserMode.SEMVER_MODE);
+        assertTrue(barSchemaContextFuture.isDone());
+        assertSchemaContext(barSchemaContextFuture.checkedGet(), 2);
+    }
+
+    @Test
+    public void testSharedSchemaRepository() throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("shared-schema-repo-test");
+
+        final SettableSchemaProvider<ASTSchemaSource> bar = getImmediateYangSourceProviderFromResource("/semantic-version/shared-schema-repository/bar@2016-01-01.yang");
+        bar.register(sharedSchemaRepository);
+        bar.setResult();
+        final SettableSchemaProvider<ASTSchemaSource> foo = getImmediateYangSourceProviderFromResource("/semantic-version/shared-schema-repository/foo.yang");
+        foo.register(sharedSchemaRepository);
+        foo.setResult();
+        final SettableSchemaProvider<ASTSchemaSource> semVer = getImmediateYangSourceProviderFromResource("/semantic-version/shared-schema-repository/semantic-version.yang");
+        semVer.register(sharedSchemaRepository);
+        semVer.setResult();
+
+        final SchemaContextFactory fact = sharedSchemaRepository
+                .createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> inetAndTopologySchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(bar.getId(), foo.getId(), semVer.getId()));
+        assertTrue(inetAndTopologySchemaContextFuture.isDone());
+        assertSchemaContext(inetAndTopologySchemaContextFuture.checkedGet(), 3);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> barSchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(bar.getId(), semVer.getId()));
+        assertTrue(barSchemaContextFuture.isDone());
+        assertSchemaContext(barSchemaContextFuture.checkedGet(), 2);
+    }
+
+    private static void assertSchemaContext(final SchemaContext schemaContext, final int moduleSize) {
+        assertNotNull(schemaContext);
+        assertEquals(moduleSize, schemaContext.getModules().size());
+    }
+
+    static SettableSchemaProvider<ASTSchemaSource> getImmediateYangSourceProviderFromResource(final String resourceName)
+            throws Exception {
+        final ResourceYangSource yangSource = new ResourceYangSource(resourceName);
+        final CheckedFuture<ASTSchemaSource, SchemaSourceException> aSTSchemaSource = TextToASTTransformer.TRANSFORMATION
+                .apply(yangSource);
+        return SettableSchemaProvider.createImmediate(aSTSchemaSource.get(), ASTSchemaSource.class);
+    }
+}
index ec3ed1253d219ed624d8298360f6bdb0c1eb37e9..d4fdc97fd31d8cd63edc7c24d9a21951292aa21e 100644 (file)
@@ -2,6 +2,8 @@ package org.opendaylight.yangtools.yang.parser.repo;
 
 import static org.junit.Assert.assertNotNull;
 
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
@@ -35,8 +37,8 @@ public class SharedSchemaContextFactoryTest {
 
         final ResourceYangSource source1 = new ResourceYangSource("/ietf/ietf-inet-types@2010-09-24.yang");
         final ResourceYangSource source2 = new ResourceYangSource("/ietf/iana-timezones@2012-07-09.yang");
-        s1 = new SourceIdentifier("ietf-inet-types", "2010-09-24");
-        s2 = new SourceIdentifier("iana-timezones", "2012-07-09");
+        s1 = RevisionSourceIdentifier.create("ietf-inet-types", "2010-09-24");
+        s2 = RevisionSourceIdentifier.create("iana-timezones", "2012-07-09");
 
         final TextToASTTransformer transformer = TextToASTTransformer.create(repository, repository);
         repository.registerSchemaSourceListener(transformer);
@@ -75,7 +77,7 @@ public class SharedSchemaContextFactoryTest {
         provider.register(repository);
 
         // Register the same provider under source id without revision
-        final SourceIdentifier sIdWithoutRevision = new SourceIdentifier(provider.getId().getName());
+        final SourceIdentifier sIdWithoutRevision = RevisionSourceIdentifier.create(provider.getId().getName());
         repository.registerSchemaSource(provider, PotentialSchemaSource.create(
                 sIdWithoutRevision, ASTSchemaSource.class, PotentialSchemaSource.Costs.IMMEDIATE.getValue()));
 
index 4e280160f24fa8d2c9ed9a12b2fe4fc2b1027aa4..b8fca69ffb9d05f56c1606aca8e6622099586372 100644 (file)
@@ -20,6 +20,9 @@ import static org.junit.Assert.fail;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+
 import com.google.common.base.Charsets;
 import com.google.common.base.Function;
 import com.google.common.base.MoreObjects;
@@ -247,10 +250,10 @@ public class SharedSchemaRepositoryTest {
             }
         };
         assertThat(Collections2.transform(listener.registeredSources, potSourceToSID),
-                both(hasItem(new SourceIdentifier("test", Optional.absent())))
-                        .and(hasItem(new SourceIdentifier("test", Optional.of("2012-12-12"))))
-                        .and(hasItem(new SourceIdentifier("test", Optional.of("2013-12-12"))))
-                        .and(hasItem(new SourceIdentifier("module", Optional.of("2010-12-12"))))
+                both(hasItem(RevisionSourceIdentifier.create("test", Optional.absent())))
+                        .and(hasItem(RevisionSourceIdentifier.create("test", Optional.of("2012-12-12"))))
+                        .and(hasItem(RevisionSourceIdentifier.create("test", Optional.of("2013-12-12"))))
+                        .and(hasItem(RevisionSourceIdentifier.create("module", Optional.of("2010-12-12"))))
         );
     }
 
@@ -263,7 +266,7 @@ public class SharedSchemaRepositoryTest {
         final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(sharedSchemaRepository, YangTextSchemaSource.class, storageDir);
         sharedSchemaRepository.registerSchemaSourceListener(cache);
 
-        final SourceIdentifier runningId = new SourceIdentifier("running", Optional.of("2012-12-12"));
+        final SourceIdentifier runningId = RevisionSourceIdentifier.create("running", Optional.of("2012-12-12"));
 
         sharedSchemaRepository.registerSchemaSource(new SchemaSourceProvider<YangTextSchemaSource>() {
             @Override
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang
new file mode 100644 (file)
index 0000000..54da0db
--- /dev/null
@@ -0,0 +1,15 @@
+module bar {
+    namespace "bar";
+    prefix bar;
+    yang-version 1;
+
+    import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
+
+    revision "2016-01-01" {
+        description "Initial version";
+    }
+    sv:semantic-version "0.1.2";
+
+    container root {
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/foo.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/foo.yang
new file mode 100644 (file)
index 0000000..dda1144
--- /dev/null
@@ -0,0 +1,16 @@
+module foo {
+    namespace "foo";
+    prefix foo;
+    yang-version 1;
+
+    import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
+    import bar { prefix bar; revision-date 2016-01-31; sv:semantic-version "0.1.2";}
+
+    revision "2016-02-01" {
+        description "Initial version";
+    }
+    sv:semantic-version "0.1.1";
+
+    container root {
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/semantic-version.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/semantic-version.yang
new file mode 100644 (file)
index 0000000..dd92de6
--- /dev/null
@@ -0,0 +1,47 @@
+module semantic-version {
+    namespace "urn:opendaylight:yang:extension:semantic-version";
+    prefix sv;
+    yang-version 1;
+
+    revision 2016-02-02 {
+        description "Initial verison";
+    }
+    sv:semantic-version "0.0.1";
+
+    extension semantic-version {
+        argument "semantic-version" {
+            yin-element false;
+        }
+        description
+            "The OpenConfig version number for the module. This is
+            expressed as a semantic version number of the form:
+              x.y.z
+            where:
+              * x corresponds to the major version,
+              * y corresponds to a minor version,
+              * z corresponds to a patch version.
+            This version corresponds to the model file within which it is
+            defined, and does not cover the whole set of OpenConfig models.
+            Where several modules are used to build up a single block of
+            functionality, the same module version is specified across each
+            file that makes up the module.
+
+            A major version number of 0 indicates that this model is still
+            in development (whether within OpenConfig or with industry
+            partners), and is potentially subject to change.
+
+            Following a release of major version 1, all modules will
+            increment major revision number where backwards incompatible
+            changes to the model are made.
+
+            The minor version is changed when features are added to the
+            model that do not impact current clients use of the model.
+
+            The patch-level version is incremented when non-feature changes
+            (such as bugfixes or clarifications to human-readable
+            descriptions that do not impact model functionality) are made
+            that maintain backwards compatibility.
+
+            The version number is stored in the module meta-data.";
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/bar@2016-01-01.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/bar@2016-01-01.yang
new file mode 100644 (file)
index 0000000..54da0db
--- /dev/null
@@ -0,0 +1,15 @@
+module bar {
+    namespace "bar";
+    prefix bar;
+    yang-version 1;
+
+    import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
+
+    revision "2016-01-01" {
+        description "Initial version";
+    }
+    sv:semantic-version "0.1.2";
+
+    container root {
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/foo.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/foo.yang
new file mode 100644 (file)
index 0000000..fd7d13f
--- /dev/null
@@ -0,0 +1,16 @@
+module foo {
+    namespace "foo";
+    prefix foo;
+    yang-version 1;
+
+    import semantic-version { prefix sv; revision-date 2016-02-02; sv:semantic-version "0.0.1"; }
+    import bar { prefix bar; revision-date 2016-01-01; sv:semantic-version "0.1.2";}
+
+    revision "2016-02-01" {
+        description "Initial version";
+    }
+    sv:semantic-version "0.1.1";
+
+    container root {
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/semantic-version.yang b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/semantic-version.yang
new file mode 100644 (file)
index 0000000..dd92de6
--- /dev/null
@@ -0,0 +1,47 @@
+module semantic-version {
+    namespace "urn:opendaylight:yang:extension:semantic-version";
+    prefix sv;
+    yang-version 1;
+
+    revision 2016-02-02 {
+        description "Initial verison";
+    }
+    sv:semantic-version "0.0.1";
+
+    extension semantic-version {
+        argument "semantic-version" {
+            yin-element false;
+        }
+        description
+            "The OpenConfig version number for the module. This is
+            expressed as a semantic version number of the form:
+              x.y.z
+            where:
+              * x corresponds to the major version,
+              * y corresponds to a minor version,
+              * z corresponds to a patch version.
+            This version corresponds to the model file within which it is
+            defined, and does not cover the whole set of OpenConfig models.
+            Where several modules are used to build up a single block of
+            functionality, the same module version is specified across each
+            file that makes up the module.
+
+            A major version number of 0 indicates that this model is still
+            in development (whether within OpenConfig or with industry
+            partners), and is potentially subject to change.
+
+            Following a release of major version 1, all modules will
+            increment major revision number where backwards incompatible
+            changes to the model are made.
+
+            The minor version is changed when features are added to the
+            model that do not impact current clients use of the model.
+
+            The patch-level version is incremented when non-feature changes
+            (such as bugfixes or clarifications to human-readable
+            descriptions that do not impact model functionality) are made
+            that maintain backwards compatibility.
+
+            The version number is stored in the module meta-data.";
+    }
+}