X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Frfc6020%2FImportStatementDefinition.java;h=537c9ec248e286eb847e7a106b7740ff6a5f4ad0;hb=b212baa59f859732bd3a799425bb420035fe6154;hp=05b74316906d8fc4b16445eb424246d5d092a569;hpb=d1f606bf178d536ab6681bc9dbf8205906bcf40d;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java index 05b7431690..537c9ec248 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java @@ -7,156 +7,329 @@ */ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; +import static java.util.Objects.requireNonNull; import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SOURCE_LINKAGE; +import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SOURCE_PRE_LINKAGE; +import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.findFirstDeclaredSubstatement; import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf; -import java.util.Set; - -import java.util.Map.Entry; -import java.util.Map; -import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement; -import com.google.common.base.Optional; +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.base.Verify; import java.net.URI; import java.util.Collection; -import java.util.Date; -import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import java.util.Optional; +import org.opendaylight.yangtools.concepts.SemVer; +import org.opendaylight.yangtools.yang.common.Revision; import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; -import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; +import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement; import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement; import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl; +import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.util.ModuleIdentifierImpl; import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace; +import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion; +import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; -import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier; +import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator; +import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToSemVerSourceIdentifier; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleIdentifier; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl; -public class ImportStatementDefinition - extends +public class ImportStatementDefinition extends AbstractStatementSupport> { + private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator + .builder(YangStmtMapping.IMPORT) + .addMandatory(YangStmtMapping.PREFIX) + .addOptional(YangStmtMapping.REVISION_DATE) + .addOptional(SupportedExtensionsMapping.OPENCONFIG_VERSION) + .build(); public ImportStatementDefinition() { - super(Rfc6020Mapping.IMPORT); + super(YangStmtMapping.IMPORT); } @Override - public String parseArgumentValue(StmtContext ctx, String value) { + public String parseArgumentValue(final StmtContext ctx, final String value) { return value; } @Override - public ImportStatement createDeclared( - StmtContext ctx) { + public ImportStatement createDeclared(final StmtContext ctx) { return new ImportStatementImpl(ctx); } @Override public EffectiveStatement createEffective( - StmtContext> ctx) { + final StmtContext> ctx) { return new ImportEffectiveStatementImpl(ctx); } @Override - public void onLinkageDeclared( - final Mutable> stmt) - throws SourceException { - final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt); - ModelActionBuilder importAction = stmt - .newInferenceAction(SOURCE_LINKAGE); - final Prerequisite> imported; - final Prerequisite> linkageTarget; - imported = importAction.requiresCtx(stmt, ModuleNamespace.class, - impIdentifier, SOURCE_LINKAGE); - linkageTarget = importAction.mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE); + public void onPreLinkageDeclared(final Mutable> stmt) { + /* + * Add ModuleIdentifier of a module which is required by this module. + * Based on this information, required modules are searched from library + * sources. + */ + stmt.addRequiredSource(RevisionImport.getImportedSourceIdentifier(stmt)); + + final String moduleName = stmt.getStatementArgument(); + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_PRE_LINKAGE); + final Prerequisite> imported = importAction.requiresCtx(stmt, + PreLinkageModuleNamespace.class, moduleName, SOURCE_PRE_LINKAGE); + final Prerequisite> linkageTarget = importAction + .mutatesCtx(stmt.getRoot(), SOURCE_PRE_LINKAGE); importAction.apply(new InferenceAction() { + @Override + public void apply(final InferenceContext ctx) { + final StmtContext importedModuleContext = imported.resolve(ctx); + Verify.verify(moduleName.equals(importedModuleContext.getStatementArgument())); + final URI importedModuleNamespace = importedModuleContext.getFromNamespace(ModuleNameToNamespace.class, + moduleName); + Verify.verifyNotNull(importedModuleNamespace); + final String impPrefix = SourceException.throwIfNull( + firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), + stmt.getStatementSourceReference(), "Missing prefix statement"); + + stmt.addToNs(ImpPrefixToNamespace.class, impPrefix, importedModuleNamespace); + } @Override - public void apply() throws InferenceException { - StmtContext importedModule = null; - ModuleIdentifier importedModuleIdentifier = null; - if (impIdentifier.getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP) { - Entry>> recentModuleEntry = findRecentModule( - impIdentifier, - stmt.getAllFromNamespace(ModuleNamespace.class)); - if (recentModuleEntry != null) { - importedModuleIdentifier = recentModuleEntry.getKey(); - importedModule = recentModuleEntry.getValue(); - } - } + public void prerequisiteFailed(final Collection> failed) { + InferenceException.throwIf(failed.contains(imported), stmt.getStatementSourceReference(), + "Imported module [%s] was not found.", moduleName); + } + }); + } - if(importedModule == null || importedModuleIdentifier == null) { - importedModule = imported.get(); - importedModuleIdentifier = impIdentifier; - } + @Override + public void onLinkageDeclared( + final Mutable> stmt) { + if (stmt.isEnabledSemanticVersioning()) { + SemanticVersionImport.onLinkageDeclared(stmt); + } else { + RevisionImport.onLinkageDeclared(stmt); + } + } + + @Override + protected SubstatementValidator getSubstatementValidator() { + return SUBSTATEMENT_VALIDATOR; + } + + private static class RevisionImport { - linkageTarget.get().addToNs(ImportedModuleContext.class, - importedModuleIdentifier, importedModule); - String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), - PrefixStatement.class); - stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, - importedModuleIdentifier); + private RevisionImport() { + throw new UnsupportedOperationException("Utility class"); + } + + private static void onLinkageDeclared( + final Mutable> stmt) { + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE); + final Prerequisite> imported; + final String moduleName = stmt.getStatementArgument(); + final Revision revision = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class); + if (revision == null) { + imported = importAction.requiresCtx(stmt, ModuleNamespace.class, + NamespaceKeyCriterion.latestRevisionModule(moduleName), SOURCE_LINKAGE); + } else { + imported = importAction.requiresCtx(stmt, ModuleNamespace.class, + ModuleIdentifierImpl.create(moduleName, Optional.of(revision)), SOURCE_LINKAGE); } - private Entry>> findRecentModule( - ModuleIdentifier impIdentifier, - Map>> allModules) { - - ModuleIdentifier recentModuleIdentifier = impIdentifier; - Entry>> recentModuleEntry = null; - - Set>>> moduleEntrySet = allModules - .entrySet(); - for (Entry>> moduleEntry : moduleEntrySet) { - if (moduleEntry.getKey().getName() - .equals(impIdentifier.getName()) - && moduleEntry - .getKey() - .getRevision() - .compareTo( - recentModuleIdentifier - .getRevision()) > 0) { - recentModuleIdentifier = moduleEntry.getKey(); - recentModuleEntry = moduleEntry; + final Prerequisite> linkageTarget = importAction.mutatesCtx(stmt.getRoot(), + SOURCE_LINKAGE); + + importAction.apply(new InferenceAction() { + @Override + public void apply(final InferenceContext ctx) { + final StmtContext importedModule = imported.resolve(ctx); + + linkageTarget.resolve(ctx).addToNs(ImportedModuleContext.class, + stmt.getFromNamespace(ModuleCtxToModuleIdentifier.class, importedModule), importedModule); + final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); + final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(), + NamespaceStatement.class); + stmt.addToNs(ImportPrefixToModuleCtx.class, impPrefix, importedModule); + stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix); + } + + @Override + public void prerequisiteFailed(final Collection> failed) { + if (failed.contains(imported)) { + throw new InferenceException(stmt.getStatementSourceReference(), + "Imported module [%s] was not found.", moduleName); } } + }); + } + + static SourceIdentifier getImportedSourceIdentifier(final StmtContext stmt) { + final StmtContext revision = findFirstDeclaredSubstatement(stmt, + RevisionDateStatement.class); + return revision == null ? RevisionSourceIdentifier.create(stmt.getStatementArgument()) + : RevisionSourceIdentifier.create(stmt.getStatementArgument(), revision.rawStatementArgument()); + } + } + + private static class SemanticVersionImport { + + private abstract static class CompatibleCriterion extends NamespaceKeyCriterion { + private final String moduleName; + + CompatibleCriterion(final String moduleName) { + this.moduleName = requireNonNull(moduleName); + } - return recentModuleEntry; + @Override + public boolean match(final SemVerSourceIdentifier key) { + return moduleName.equals(key.getName()); } @Override - public void prerequisiteFailed( - Collection> failed) - throws InferenceException { - if (failed.contains(imported)) { - throw new InferenceException(String.format( - "Imported module [%s] was not found.", - impIdentifier), stmt.getStatementSourceReference()); + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper.add("moduleName", moduleName); + } + } + + private static final class NoVerCompatibleCriterion extends CompatibleCriterion { + NoVerCompatibleCriterion(final String moduleName) { + super(moduleName); + } + + @Override + public SemVerSourceIdentifier select(final SemVerSourceIdentifier first, + final SemVerSourceIdentifier second) { + // TODO Auto-generated method stub + return null; + } + } + + private static final class SemVerCompatibleCriterion extends CompatibleCriterion { + private final SemVer semVer; + + SemVerCompatibleCriterion(final String moduleName, final SemVer semVer) { + super(moduleName); + this.semVer = requireNonNull(semVer); + } + + @Override + public boolean match(final SemVerSourceIdentifier key) { + if (!super.match(key)) { + return false; + } + final Optional optKeyVer = key.getSemanticVersion(); + if (!optKeyVer.isPresent()) { + return false; } + + final SemVer keyVer = optKeyVer.get(); + if (semVer.getMajor() != keyVer.getMajor()) { + return false; + } + if (semVer.getMinor() > keyVer.getMinor()) { + return false; + } + return semVer.getMinor() < keyVer.getMinor() || semVer.getPatch() <= keyVer.getPatch(); } - }); - } - private static ModuleIdentifier getImportedModuleIdentifier( - Mutable stmt) throws SourceException { + @Override + public SemVerSourceIdentifier select(final SemVerSourceIdentifier first, + final SemVerSourceIdentifier second) { + return first.getSemanticVersion().get().compareTo(second.getSemanticVersion().get()) >= 0 ? first + : second; + } - String moduleName = stmt.getStatementArgument(); - Date revision = firstAttributeOf(stmt.declaredSubstatements(), - RevisionDateStatement.class); - if (revision == null) { - revision = SimpleDateFormatUtil.DEFAULT_DATE_IMP; + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return super.addToStringAttributes(toStringHelper).add("version", semVer); + } } - return new ModuleIdentifierImpl(moduleName, Optional. absent(), - Optional. of(revision)); - } -} \ No newline at end of file + private SemanticVersionImport() { + throw new UnsupportedOperationException("Utility class"); + } + + private static void onLinkageDeclared( + final Mutable> stmt) { + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE); + final String moduleName = stmt.getStatementArgument(); + final SemVer semanticVersion = stmt.getFromNamespace(SemanticVersionNamespace.class, stmt); + final CompatibleCriterion criterion = semanticVersion == null ? new NoVerCompatibleCriterion(moduleName) + : new SemVerCompatibleCriterion(moduleName, semanticVersion); + + final Prerequisite> imported = importAction.requiresCtx(stmt, + SemanticVersionModuleNamespace.class, criterion, SOURCE_LINKAGE); + final Prerequisite> linkageTarget = importAction.mutatesCtx(stmt.getRoot(), + SOURCE_LINKAGE); + + importAction.apply(new InferenceAction() { + @Override + public void apply(final InferenceContext ctx) { + final StmtContext importedModule = imported.resolve(ctx); + final SemVer importedVersion = stmt.getFromNamespace(SemanticVersionNamespace.class, stmt); + final ModuleIdentifier importedModuleIdentifier = importedModule.getFromNamespace( + ModuleCtxToModuleIdentifier.class, importedModule); + final SemVerSourceIdentifier semVerModuleIdentifier = createSemVerModuleIdentifier( + importedModuleIdentifier, importedVersion); + + linkageTarget.resolve(ctx).addToNs(ImportedModuleContext.class, importedModuleIdentifier, + importedModule); + final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); + stmt.addToNs(ImportPrefixToModuleCtx.class, impPrefix, importedModule); + stmt.addToNs(ImportPrefixToSemVerSourceIdentifier.class, impPrefix, semVerModuleIdentifier); + + final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(), + NamespaceStatement.class); + stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix); + } + + @Override + public void prerequisiteFailed(final Collection> failed) { + if (failed.contains(imported)) { + throw new InferenceException(stmt.getStatementSourceReference(), + "Unable to find module compatible with requested import [%s(%s)].", moduleName, + getRequestedImportVersionString(stmt)); + } + } + }); + } + + private static Optional getRequestedImportVersion(final StmtContext stmt) { + return Optional.ofNullable(stmt.getFromNamespace(SemanticVersionNamespace.class, stmt)); + } + + private static String getRequestedImportVersionString(final StmtContext stmt) { + return getRequestedImportVersion(stmt).map(SemVer::toString).orElse(""); + } + + private static SemVerSourceIdentifier createSemVerModuleIdentifier( + final ModuleIdentifier importedModuleIdentifier, final SemVer semVer) { + final String formattedRevision = importedModuleIdentifier.getRevision().map(Revision::toString) + .orElse(null); + return SemVerSourceIdentifier.create(importedModuleIdentifier.getName(), formattedRevision, semVer); + } + } +}