X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Frfc6020%2FImportStatementDefinition.java;h=74fb2afd1bbaca846a058aae005f7d1a2dec2607;hb=refs%2Fchanges%2F98%2F49798%2F4;hp=6863486d68914fe7473c25552ff5d4884043e58a;hpb=bcb500b00c6b24089ef8a949625ad477c34f91ae;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 6863486d68..74fb2afd1b 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 @@ -8,105 +8,299 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; 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.firstAttributeOf; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl; - -import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier; -import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement; -import com.google.common.base.Optional; +import com.google.common.base.Verify; import java.net.URI; -import java.text.ParseException; import java.util.Collection; import java.util.Date; +import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.Optional; +import org.opendaylight.yangtools.concepts.SemVer; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.model.api.Module; 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.ModuleStatement; +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.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.SubstatementValidator; 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.Prerequisite; +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.source.ImpPrefixToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToSemVerModuleIdentifier; +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 AbstractStatementSupport> { + private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator + .builder(YangStmtMapping.IMPORT) + .addMandatory(YangStmtMapping.PREFIX) + .addOptional(YangStmtMapping.REVISION_DATE) + .addOptional(SupportedExtensionsMapping.SEMANTIC_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); - - String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); - stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, impIdentifier); + public void onPreLinkageDeclared(final Mutable> 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() throws InferenceException { - StmtContext importedModule = imported.get(); - linkageTarget.get().addToNs(ImportedModuleContext.class, impIdentifier, importedModule); + public void apply() { + StmtContext importedModuleContext = imported.get(); + 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 prerequisiteFailed(Collection> failed) throws InferenceException { - if (failed.contains(imported)) { - throw new InferenceException("Imported module was not found.", stmt.getStatementSourceReference()); - } + public void prerequisiteFailed(final Collection> failed) { + InferenceException.throwIf(failed.contains(imported), stmt.getStatementSourceReference(), + "Imported module [%s] was not found.", moduleName); } }); } - private static ModuleIdentifier getImportedModuleIdentifier(Mutable stmt) - throws SourceException { - - String moduleName = stmt.getStatementArgument(); - String revisionArg = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class); - final Optional revision; - if (revisionArg != null) { - try { - revision = Optional.of(SimpleDateFormatUtil.getRevisionFormat().parse(revisionArg)); - } catch (ParseException e) { - throw new SourceException(String.format("Revision value %s is not in required format yyyy-MM-dd", - revisionArg), stmt.getStatementSourceReference(), e); - } + @Override + public void onLinkageDeclared( + final Mutable> stmt) { + if (stmt.isEnabledSemanticVersioning()) { + SemanticVersionImport.onLinkageDeclared(stmt); } else { - revision = Optional.of(SimpleDateFormatUtil.DEFAULT_DATE_IMP); + RevisionImport.onLinkageDeclared(stmt); } - return new ModuleIdentifierImpl(moduleName, Optional. absent(), revision); } -} \ No newline at end of file + @Override + protected SubstatementValidator getSubstatementValidator() { + return SUBSTATEMENT_VALIDATOR; + } + + private static class RevisionImport { + + private RevisionImport() { + throw new UnsupportedOperationException("Utility class"); + } + + private static void onLinkageDeclared( + final Mutable> stmt) { + final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt); + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE); + final Prerequisite> imported = importAction.requiresCtx(stmt, ModuleNamespace.class, + impIdentifier, SOURCE_LINKAGE); + final Prerequisite> linkageTarget = importAction + .mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE); + + importAction.apply(new InferenceAction() { + @Override + public void apply() { + 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(); + } + } + + if (importedModule == null || importedModuleIdentifier == null) { + importedModule = imported.get(); + importedModuleIdentifier = impIdentifier; + } + + linkageTarget.get().addToNs(ImportedModuleContext.class, importedModuleIdentifier, importedModule); + String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); + stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, importedModuleIdentifier); + + 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(), + "Imported module [%s] was not found.", impIdentifier); + } + } + }); + + } + + private static Entry>> findRecentModule( + final ModuleIdentifier impIdentifier, + final Map>> allModules) { + + ModuleIdentifier recentModuleIdentifier = impIdentifier; + Entry>> recentModuleEntry = null; + + for (Entry>> moduleEntry : allModules + .entrySet()) { + final ModuleIdentifier id = moduleEntry.getKey(); + + if (id.getName().equals(impIdentifier.getName()) + && id.getRevision().compareTo(recentModuleIdentifier.getRevision()) > 0) { + recentModuleIdentifier = id; + recentModuleEntry = moduleEntry; + } + } + + return recentModuleEntry; + } + + private static ModuleIdentifier getImportedModuleIdentifier(final Mutable stmt) { + Date revision = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class); + if (revision == null) { + revision = SimpleDateFormatUtil.DEFAULT_DATE_IMP; + } + + return ModuleIdentifierImpl.create(stmt.getStatementArgument(), Optional.empty(), Optional.of(revision)); + } + } + + private static class SemanticVersionImport { + private SemanticVersionImport() { + throw new UnsupportedOperationException("Utility class"); + } + + private static void onLinkageDeclared( + final Mutable> stmt) { + final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt); + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE); + final Prerequisite> imported = importAction.requiresCtx(stmt, ModuleNamespace.class, + impIdentifier, SOURCE_LINKAGE); + final Prerequisite> linkageTarget = importAction + .mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE); + + importAction.apply(new InferenceAction() { + @Override + public void apply() { + Entry> importedModuleEntry= findRecentCompatibleModuleEntry( + impIdentifier.getName(), stmt); + + StmtContext importedModule = null; + ModuleIdentifier importedModuleIdentifier = null; + ModuleIdentifier semVerModuleIdentifier = null; + if (importedModuleEntry != null) { + importedModule = importedModuleEntry.getValue(); + importedModuleIdentifier = importedModule.getFromNamespace(ModuleCtxToModuleIdentifier.class, importedModule); + semVerModuleIdentifier = createSemVerModuleIdentifier(importedModuleIdentifier, importedModuleEntry.getKey()); + } else { + throw new InferenceException(stmt.getStatementSourceReference(), + "Unable to find module compatible with requested import [%s(%s)].", impIdentifier + .getName(), getRequestedImportVersion(stmt)); + } + + linkageTarget.get().addToNs(ImportedModuleContext.class, importedModuleIdentifier, importedModule); + String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); + stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, importedModuleIdentifier); + stmt.addToNs(ImpPrefixToSemVerModuleIdentifier.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)].", impIdentifier + .getName(), getRequestedImportVersion(stmt)); + } + } + }); + } + + private static SemVer getRequestedImportVersion(final Mutable impStmt) { + SemVer requestedImportVersion = impStmt.getFromNamespace(SemanticVersionNamespace.class, impStmt); + if (requestedImportVersion == null) { + requestedImportVersion = Module.DEFAULT_SEMANTIC_VERSION; + } + return requestedImportVersion; + } + + private static Entry> findRecentCompatibleModuleEntry(final String moduleName, + final Mutable> impStmt) { + NavigableMap> allRelevantModulesMap = impStmt.getFromNamespace( + SemanticVersionModuleNamespace.class, moduleName); + if (allRelevantModulesMap == null) { + return null; + } + + final SemVer requestedImportVersion = getRequestedImportVersion(impStmt); + allRelevantModulesMap = allRelevantModulesMap.subMap(requestedImportVersion, true, + SemVer.create(requestedImportVersion.getMajor() + 1), false); + if (!allRelevantModulesMap.isEmpty()) { + return allRelevantModulesMap.lastEntry(); + } + + return null; + } + + private static ModuleIdentifier getImportedModuleIdentifier(final Mutable impStmt) { + return ModuleIdentifierImpl.create(impStmt.getStatementArgument(), Optional.empty(), + Optional.of(SimpleDateFormatUtil.DEFAULT_DATE_IMP)); + } + + private static ModuleIdentifier createSemVerModuleIdentifier(final ModuleIdentifier importedModuleIdentifier, + final SemVer semVer) { + return ModuleIdentifierImpl.create(importedModuleIdentifier.getName(), + Optional.ofNullable(importedModuleIdentifier.getNamespace()), + Optional.of(importedModuleIdentifier.getRevision()), semVer); + } + } +}