From: Peter Kajsa Date: Thu, 14 Apr 2016 09:28:29 +0000 (+0200) Subject: Bug 4662: Introduce a SemanticVersion concept - SchemaContextFactory X-Git-Tag: release/boron~111 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=e403e34bcb508c48aa606a1cd81a386fb73c5db6;hp=8b74f965b8a7cb7d592c84e87bda32bcefd06162;p=yangtools.git Bug 4662: Introduce a SemanticVersion concept - SchemaContextFactory Introducing of semantic version concept into SchemaContextFactory. Change-Id: I382d6d6107852cd39a8e4023bbf2ae4d079782c7 Signed-off-by: Peter Kajsa --- 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 index 0000000000..b12b2360a4 --- /dev/null +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/RevisionSourceIdentifier.java @@ -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 + * + * + * Revision source identifier is designated to be carry only necessary + * information to look-up YANG model source and to be used by various + * SchemaSourceProviders. + * + * Note:On source retrieval layer it is impossible to distinguish between + * YANG module and/or submodule unless source is present. + * + *

+ * (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 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 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() + "]"; + } +} diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java index 9b338a742b..ddf9c53770 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java @@ -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 createSchemaContext( @Nonnull Collection 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 createSchemaContext( + Collection 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 createSchemaContext( + @Nonnull Collection requiredSources, Predicate 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 createSchemaContext( - @Nonnull Collection requiredSources, Predicate isFeatureSupported); + Collection requiredSources, StatementParserMode statementParserMode, + Predicate 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 index 0000000000..88f5168d7f --- /dev/null +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SemVerSourceIdentifier.java @@ -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 + *

+ * + * Source identifier is designated to be carry only necessary information to + * look-up YANG model source and to be used by various SchemaSourceProviders. + * + * Note:On source retrieval layer it is impossible to distinguish between + * YANG module and/or submodule unless source is present. + * + *

+ * (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 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 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() + "]"; + } +} diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java index fba3630573..48ce2a7c0b 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SourceIdentifier.java @@ -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 - *

+ * 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. - * - * Note:On source retrieval layer it is impossible to distinguish - * between YANG module and/or submodule unless source is present. - * - *

- * (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. *

- * 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 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 formattedRevision) { + SourceIdentifier(final String name, final Optional 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 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 - * name ['@' revision] '.yang' + * Returns filename in format name ['@' revision] '.yang' *

- * Where revision is date in format YYYY-mm-dd. + * Where revision is date in format YYYY-mm-dd. *

* * @see RFC6020 @@ -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 - * moduleName ['@' revision] '.yang' + * Returns filename in format moduleName ['@' revision] '.yang' * * Where Where revision-date is in format YYYY-mm-dd. * *

- * 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(); } - } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCache.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCache.java index 6a4b83a5eb..9915334bae 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCache.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/FilesystemSchemaSourceCache.java @@ -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 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 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 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 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; } diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCacheTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCacheTest.java index 2fa8575120..14d5e2ffce 100644 --- a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCacheTest.java +++ b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/InMemorySchemaSourceCacheTest.java @@ -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 checkedSource = inMemorySchemaSourceCache .getSource(sourceIdentifier); Assert.assertNotNull(checkedSource); @@ -90,7 +92,7 @@ public class InMemorySchemaSourceCacheTest { public void inMemorySchemaSourceCacheNullGetSourcestest() throws Exception { final InMemorySchemaSourceCache 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 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 checkedSource = inMemorySchemaSourceCache .getSource(sourceIdentifier); final CheckedFuture 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; } diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java index 20a43df62d..461dcf6c73 100644 --- a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java +++ b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java @@ -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 foo = new Foo<>(sourceIdentifier, SchemaSourceTransformerTest.SRC_CLASS, PotentialSchemaSource.Costs.COMPUTATION); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java index e7125bf4ad..e92fb61edf 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java @@ -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; private final ImmutableSet submoduleIncludes; private final ImmutableSet moduleImports; private final ImmutableSet dependencies; @@ -68,6 +71,13 @@ public abstract class YangModelDependencyInfo { YangModelDependencyInfo(final String name, final String formattedRevision, final ImmutableSet imports, final ImmutableSet includes) { + this(name, formattedRevision, imports, includes, Optional.absent()); + } + + YangModelDependencyInfo(final String name, final String formattedRevision, + final ImmutableSet imports, + final ImmutableSet includes, + final Optional semVer) { this.name = name; this.formattedRevision = formattedRevision; this.revision = formattedRevision == null ? null : QName @@ -76,6 +86,7 @@ public abstract class YangModelDependencyInfo { this.submoduleIncludes = includes; this.dependencies = ImmutableSet. 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 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 imports = parseImports(module + final String name = getArgumentString(module); + final String latestRevision = getLatestRevision(module.revision_stmts()); + final ImmutableSet imports = parseImports(module .linkage_stmts().import_stmt()); - ImmutableSet includes = parseIncludes(module + final ImmutableSet 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 imports = parseImports(module); - ImmutableSet includes = parseIncludes(module); + final String name = Utils.stringFromStringContext(module.argument()); + final String latestRevision = getLatestRevision(module); + final Optional semVer = Optional.fromNullable(getSemanticVersion(module)); + final ImmutableSet imports = parseImports(module); + final ImmutableSet includes = parseIncludes(module); - return new ModuleDependencyInfo(name, latestRevision, imports, includes); + return new ModuleDependencyInfo(name, latestRevision, imports, includes, semVer); } private static ImmutableSet parseImports( final YangStatementParser.StatementContext module) { - Set result = new HashSet<>(); - List subStatements = module.statement(); - for (StatementContext subStatementContext : subStatements) { + final Set result = new HashSet<>(); + final List 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 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 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 parseIncludes( final YangStatementParser.StatementContext module) { - Set result = new HashSet<>(); - List subStatements = module.statement(); - for (StatementContext subStatementContext : subStatements) { + final Set result = new HashSet<>(); + final List 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 importSubStatements = importStatement + private static String getRevisionDateString(final StatementContext importStatement) { + final List 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 parseImports( final List importStatements) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Import_stmtContext importStmt : importStatements) { - String moduleName = getArgumentString(importStmt); - Date revision = getRevision(importStmt.revision_date_stmt()); + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (final Import_stmtContext importStmt : importStatements) { + final String moduleName = getArgumentString(importStmt); + final Date revision = getRevision(importStmt.revision_date_stmt()); builder.add(new ModuleImportImpl(moduleName, revision)); } return builder.build(); @@ -322,15 +368,15 @@ public abstract class YangModelDependencyInfo { public static String getLatestRevision( final YangStatementParser.StatementContext module) { - List subStatements = module.statement(); + final List 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 revisions = revisionStmts + final List 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 imports = parseImports(submodule); - ImmutableSet includes = parseIncludes(submodule); + final String latestRevision = getLatestRevision(submodule); + final ImmutableSet imports = parseImports(submodule); + final ImmutableSet includes = parseIncludes(submodule); return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes); } - private static String parseBelongsTo(StatementContext submodule) { - List subStatements = submodule.statement(); - for (StatementContext subStatementContext : subStatements) { + private static String parseBelongsTo(final StatementContext submodule) { + final List 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 imports = parseImports(submodule + final String latestRevision = getLatestRevision(submodule.revision_stmts()); + final ImmutableSet imports = parseImports(submodule .linkage_stmts().import_stmt()); - ImmutableSet includes = parseIncludes(submodule + final ImmutableSet includes = parseIncludes(submodule .linkage_stmts().include_stmt()); return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, @@ -403,10 +449,10 @@ public abstract class YangModelDependencyInfo { private static ImmutableSet parseIncludes( final List importStatements) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Include_stmtContext importStmt : importStatements) { - String moduleName = getArgumentString(importStmt); - Date revision = getRevision(importStmt.revision_date_stmt()); + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for (final Include_stmtContext importStmt : importStatements) { + final String moduleName = getArgumentString(importStmt); + final Date revision = getRevision(importStmt.revision_date_stmt()); builder.add(new ModuleImportImpl(moduleName, revision)); } return builder.build(); @@ -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 imports, + final ImmutableSet includes, + final Optional semVer) { + super(name, latestRevision, imports, includes, semVer); + } + @Override public String toString() { - return "Module [name=" + getName() + ", revision=" + getRevision() - + ", dependencies=" + getDependencies() + "]"; + return "Module [name=" + getName() + ", revision=" + getRevision() + ", semanticVersion=" + + getSemanticVersion().or(Module.DEFAULT_SEMANTIC_VERSION) + ", dependencies=" + getDependencies() + + "]"; } } @@ -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) { 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() + "]"; } } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java index d24e8ae116..bc339f7f54 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java @@ -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 resolvedSources; private final Collection unresolvedSources; private final Multimap unsatisfiedImports; - public DependencyResolver(final Collection resolvedSources, - final Collection unresolvedSources, final Multimap unsatisfiedImports) { - this.resolvedSources = Preconditions.checkNotNull(resolvedSources); - this.unresolvedSources = Preconditions.checkNotNull(unresolvedSources); - this.unsatisfiedImports = Preconditions.checkNotNull(unsatisfiedImports); - } - - private static SourceIdentifier findWildcard(final Iterable haystack, final String needle) { - for (final SourceIdentifier r : haystack) { - if (r.getName().equals(needle)) { - return r; - } - } - - return null; - } - - private static boolean isKnown(final Collection 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 depInfo) { + protected DependencyResolver(final Map depInfo) { final Collection resolved = new ArrayList<>(depInfo.size()); final Collection pending = new ArrayList<>(depInfo.keySet()); final Map submodules = Maps.newHashMap(); @@ -130,23 +95,23 @@ final class DependencyResolver { } } - if (!pending.isEmpty()) { - final Multimap 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 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 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 index 0000000000..7239ff5023 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/RevisionDependencyResolver.java @@ -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 depInfo) { + super(depInfo); + } + + protected static SourceIdentifier findWildcard(final Iterable haystack, final String needle) { + for (final SourceIdentifier r : haystack) { + if (needle.equals(r.getName())) { + return r; + } + } + + return null; + } + + @Override + protected boolean isKnown(final Collection 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 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 index 0000000000..8567254762 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SemVerDependencyResolver.java @@ -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 depInfo) { + super(depInfo); + } + + protected static SourceIdentifier findCompatibleVersion(final Iterable 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 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 depInfo) { + return new SemVerDependencyResolver(depInfo); + } +} \ No newline at end of file diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java index 1594fd4212..7b40342003 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java @@ -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, SchemaContext> cache = CacheBuilder.newBuilder().weakValues().build(); + private final Cache, 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 createSchemaContext( - final Collection requiredSources, java.util.function.Predicate isFeatureSupported) { + final Collection requiredSources, final StatementParserMode statementParserMode, + final java.util.function.Predicate isFeatureSupported) { + return createSchemaContext(requiredSources, + statementParserMode == StatementParserMode.SEMVER_MODE ? this.semVerCache : this.cache, + new AssembleSources(isFeatureSupported, statementParserMode)); + } + + private CheckedFuture createSchemaContext(final Collection requiredSources, final Cache, SchemaContext> cache, final AsyncFunction, SchemaContext> assembleSources) { // Make sources unique final List 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 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, SchemaContext> { private final java.util.function.Predicate isFeatureSupported; + private final StatementParserMode statementParserMode; + private final Function getIdentifier; - private AssembleSources(final java.util.function.Predicate isFeatureSupported) { + private AssembleSources(final java.util.function.Predicate 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 apply(List sources) throws SchemaResolutionException, + public ListenableFuture apply(final List sources) throws SchemaResolutionException, SourceException, ReactorException { - final Map srcs = - Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER); + final Map srcs = Maps.uniqueIndex(sources, getIdentifier); final Map 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 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 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); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java index 3a79452e7a..a2bbcd8401 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java @@ -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 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 getSchemaContext(StatementParserMode statementParserMode) { final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT); Optional sc; Object v; @@ -201,7 +217,7 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem } while (v != version); while (true) { - final CheckedFuture f = factory.createSchemaContext(sources); + final CheckedFuture f = factory.createSchemaContext(sources, statementParserMode); try { sc = Optional.of(f.checkedGet()); break; diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java index 593899da89..c797294da5 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java @@ -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 JAVA_UNICODE_BLOCKS = ImmutableSet.builder() @@ -385,6 +386,14 @@ public final class Utils { return identifier; } + public static String trimPrefix(final String identifier) { + List 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 diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java index ab57ab74f9..ed914e2f13 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ASTSchemaSource.java @@ -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 GET_SEMVER_IDENTIFIER = new Function() { + @Override + public SemVerSourceIdentifier apply(@Nonnull final ASTSchemaSource input) { + Preconditions.checkNotNull(input); + return input.getSemVerIdentifier(); + } + }; public static final Function GET_DEPINFO = new Function() { @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 getType() { return ASTSchemaSource.class; diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java index aa1b73e5c9..aed627fd54 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/TextToASTTransformer.java @@ -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 bar = getImmediateYangSourceProviderFromResource("/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang"); + bar.register(sharedSchemaRepository); + bar.setResult(); + final SettableSchemaProvider foo = getImmediateYangSourceProviderFromResource("/semantic-version/semver-shared-schema-repository/foo.yang"); + foo.register(sharedSchemaRepository); + foo.setResult(); + final SettableSchemaProvider 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 inetAndTopologySchemaContextFuture = fact + .createSchemaContext(Lists.newArrayList(bar.getId(), foo.getId(), semVer.getId()), StatementParserMode.SEMVER_MODE); + assertTrue(inetAndTopologySchemaContextFuture.isDone()); + assertSchemaContext(inetAndTopologySchemaContextFuture.checkedGet(), 3); + + final CheckedFuture 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 bar = getImmediateYangSourceProviderFromResource("/semantic-version/shared-schema-repository/bar@2016-01-01.yang"); + bar.register(sharedSchemaRepository); + bar.setResult(); + final SettableSchemaProvider foo = getImmediateYangSourceProviderFromResource("/semantic-version/shared-schema-repository/foo.yang"); + foo.register(sharedSchemaRepository); + foo.setResult(); + final SettableSchemaProvider 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 inetAndTopologySchemaContextFuture = fact + .createSchemaContext(Lists.newArrayList(bar.getId(), foo.getId(), semVer.getId())); + assertTrue(inetAndTopologySchemaContextFuture.isDone()); + assertSchemaContext(inetAndTopologySchemaContextFuture.checkedGet(), 3); + + final CheckedFuture 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 getImmediateYangSourceProviderFromResource(final String resourceName) + throws Exception { + final ResourceYangSource yangSource = new ResourceYangSource(resourceName); + final CheckedFuture aSTSchemaSource = TextToASTTransformer.TRANSFORMATION + .apply(yangSource); + return SettableSchemaProvider.createImmediate(aSTSchemaSource.get(), ASTSchemaSource.class); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactoryTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactoryTest.java index ec3ed1253d..d4fdc97fd3 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactoryTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactoryTest.java @@ -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())); diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryTest.java index 4e280160f2..b8fca69ffb 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryTest.java @@ -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 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() { @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 index 0000000000..54da0db564 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/bar@2016-01-01.yang @@ -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 index 0000000000..dda1144dff --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/foo.yang @@ -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 index 0000000000..dd92de6883 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/semver-shared-schema-repository/semantic-version.yang @@ -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 index 0000000000..54da0db564 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/bar@2016-01-01.yang @@ -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 index 0000000000..fd7d13f655 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/foo.yang @@ -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 index 0000000000..dd92de6883 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/semantic-version/shared-schema-repository/semantic-version.yang @@ -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."; + } +}