2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SOURCE_LINKAGE;
12 import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SOURCE_PRE_LINKAGE;
13 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.findFirstDeclaredSubstatement;
14 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
16 import com.google.common.base.MoreObjects.ToStringHelper;
17 import com.google.common.base.Verify;
19 import java.util.Collection;
20 import java.util.Optional;
21 import org.opendaylight.yangtools.concepts.SemVer;
22 import org.opendaylight.yangtools.yang.common.Revision;
23 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
29 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
30 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
31 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
32 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
33 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
40 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
41 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
42 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
46 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
47 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
48 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToSemVerSourceIdentifier;
49 import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext;
50 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
51 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
52 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
53 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl;
55 public class ImportStatementDefinition extends
56 AbstractStatementSupport<String, ImportStatement, EffectiveStatement<String, ImportStatement>> {
57 private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator
58 .builder(YangStmtMapping.IMPORT)
59 .addMandatory(YangStmtMapping.PREFIX)
60 .addOptional(YangStmtMapping.REVISION_DATE)
61 .addOptional(SupportedExtensionsMapping.OPENCONFIG_VERSION)
64 public ImportStatementDefinition() {
65 super(YangStmtMapping.IMPORT);
69 public String parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
74 public ImportStatement createDeclared(final StmtContext<String, ImportStatement, ?> ctx) {
75 return new ImportStatementImpl(ctx);
79 public EffectiveStatement<String, ImportStatement> createEffective(
80 final StmtContext<String, ImportStatement, EffectiveStatement<String, ImportStatement>> ctx) {
81 return new ImportEffectiveStatementImpl(ctx);
85 public void onPreLinkageDeclared(final Mutable<String, ImportStatement,
86 EffectiveStatement<String, ImportStatement>> stmt) {
88 * Add ModuleIdentifier of a module which is required by this module.
89 * Based on this information, required modules are searched from library
92 stmt.addRequiredSource(RevisionImport.getImportedSourceIdentifier(stmt));
94 final String moduleName = stmt.getStatementArgument();
95 final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_PRE_LINKAGE);
96 final Prerequisite<StmtContext<?, ?, ?>> imported = importAction.requiresCtx(stmt,
97 PreLinkageModuleNamespace.class, moduleName, SOURCE_PRE_LINKAGE);
98 final Prerequisite<Mutable<?, ?, ?>> linkageTarget = importAction
99 .mutatesCtx(stmt.getRoot(), SOURCE_PRE_LINKAGE);
101 importAction.apply(new InferenceAction() {
103 public void apply(final InferenceContext ctx) {
104 final StmtContext<?, ?, ?> importedModuleContext = imported.resolve(ctx);
105 Verify.verify(moduleName.equals(importedModuleContext.getStatementArgument()));
106 final URI importedModuleNamespace = importedModuleContext.getFromNamespace(ModuleNameToNamespace.class,
108 Verify.verifyNotNull(importedModuleNamespace);
109 final String impPrefix = SourceException.throwIfNull(
110 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class),
111 stmt.getStatementSourceReference(), "Missing prefix statement");
113 stmt.addToNs(ImpPrefixToNamespace.class, impPrefix, importedModuleNamespace);
117 public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
118 InferenceException.throwIf(failed.contains(imported), stmt.getStatementSourceReference(),
119 "Imported module [%s] was not found.", moduleName);
125 public void onLinkageDeclared(
126 final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
127 if (stmt.isEnabledSemanticVersioning()) {
128 SemanticVersionImport.onLinkageDeclared(stmt);
130 RevisionImport.onLinkageDeclared(stmt);
135 protected SubstatementValidator getSubstatementValidator() {
136 return SUBSTATEMENT_VALIDATOR;
139 private static class RevisionImport {
141 private RevisionImport() {
142 throw new UnsupportedOperationException("Utility class");
145 private static void onLinkageDeclared(
146 final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
147 final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE);
148 final Prerequisite<StmtContext<?, ?, ?>> imported;
149 final String moduleName = stmt.getStatementArgument();
150 final Revision revision = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class);
151 if (revision == null) {
152 imported = importAction.requiresCtx(stmt, ModuleNamespace.class,
153 NamespaceKeyCriterion.latestRevisionModule(moduleName), SOURCE_LINKAGE);
155 imported = importAction.requiresCtx(stmt, ModuleNamespace.class,
156 RevisionSourceIdentifier.create(moduleName, Optional.of(revision)), SOURCE_LINKAGE);
159 final Prerequisite<Mutable<?, ?, ?>> linkageTarget = importAction.mutatesCtx(stmt.getRoot(),
162 importAction.apply(new InferenceAction() {
164 public void apply(final InferenceContext ctx) {
165 final StmtContext<?, ?, ?> importedModule = imported.resolve(ctx);
167 linkageTarget.resolve(ctx).addToNs(ImportedModuleContext.class,
168 stmt.getFromNamespace(ModuleCtxToSourceIdentifier.class, importedModule), importedModule);
169 final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
170 final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(),
171 NamespaceStatement.class);
172 stmt.addToNs(ImportPrefixToModuleCtx.class, impPrefix, importedModule);
173 stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix);
177 public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
178 if (failed.contains(imported)) {
179 throw new InferenceException(stmt.getStatementSourceReference(),
180 "Imported module [%s] was not found.", moduleName);
186 static SourceIdentifier getImportedSourceIdentifier(final StmtContext<String, ImportStatement, ?> stmt) {
187 final StmtContext<Revision, ?, ?> revision = findFirstDeclaredSubstatement(stmt,
188 RevisionDateStatement.class);
189 return revision == null ? RevisionSourceIdentifier.create(stmt.getStatementArgument())
190 : RevisionSourceIdentifier.create(stmt.getStatementArgument(), revision.getStatementArgument());
194 private static class SemanticVersionImport {
196 private abstract static class CompatibleCriterion extends NamespaceKeyCriterion<SemVerSourceIdentifier> {
197 private final String moduleName;
199 CompatibleCriterion(final String moduleName) {
200 this.moduleName = requireNonNull(moduleName);
204 public boolean match(final SemVerSourceIdentifier key) {
205 return moduleName.equals(key.getName());
209 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
210 return toStringHelper.add("moduleName", moduleName);
214 private static final class NoVerCompatibleCriterion extends CompatibleCriterion {
215 NoVerCompatibleCriterion(final String moduleName) {
220 public SemVerSourceIdentifier select(final SemVerSourceIdentifier first,
221 final SemVerSourceIdentifier second) {
222 // TODO Auto-generated method stub
227 private static final class SemVerCompatibleCriterion extends CompatibleCriterion {
228 private final SemVer semVer;
230 SemVerCompatibleCriterion(final String moduleName, final SemVer semVer) {
232 this.semVer = requireNonNull(semVer);
236 public boolean match(final SemVerSourceIdentifier key) {
237 if (!super.match(key)) {
240 final Optional<SemVer> optKeyVer = key.getSemanticVersion();
241 if (!optKeyVer.isPresent()) {
245 final SemVer keyVer = optKeyVer.get();
246 if (semVer.getMajor() != keyVer.getMajor()) {
249 if (semVer.getMinor() > keyVer.getMinor()) {
252 return semVer.getMinor() < keyVer.getMinor() || semVer.getPatch() <= keyVer.getPatch();
256 public SemVerSourceIdentifier select(final SemVerSourceIdentifier first,
257 final SemVerSourceIdentifier second) {
258 return first.getSemanticVersion().get().compareTo(second.getSemanticVersion().get()) >= 0 ? first
263 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
264 return super.addToStringAttributes(toStringHelper).add("version", semVer);
269 private SemanticVersionImport() {
270 throw new UnsupportedOperationException("Utility class");
273 private static void onLinkageDeclared(
274 final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
275 final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE);
276 final String moduleName = stmt.getStatementArgument();
277 final SemVer semanticVersion = stmt.getFromNamespace(SemanticVersionNamespace.class, stmt);
278 final CompatibleCriterion criterion = semanticVersion == null ? new NoVerCompatibleCriterion(moduleName)
279 : new SemVerCompatibleCriterion(moduleName, semanticVersion);
281 final Prerequisite<StmtContext<?, ?, ?>> imported = importAction.requiresCtx(stmt,
282 SemanticVersionModuleNamespace.class, criterion, SOURCE_LINKAGE);
283 final Prerequisite<Mutable<?, ?, ?>> linkageTarget = importAction.mutatesCtx(stmt.getRoot(),
286 importAction.apply(new InferenceAction() {
288 public void apply(final InferenceContext ctx) {
289 final StmtContext<?, ?, ?> importedModule = imported.resolve(ctx);
290 final SemVer importedVersion = stmt.getFromNamespace(SemanticVersionNamespace.class, stmt);
291 final SourceIdentifier importedModuleIdentifier = importedModule.getFromNamespace(
292 ModuleCtxToSourceIdentifier.class, importedModule);
293 final SemVerSourceIdentifier semVerModuleIdentifier = createSemVerModuleIdentifier(
294 importedModuleIdentifier, importedVersion);
296 linkageTarget.resolve(ctx).addToNs(ImportedModuleContext.class, importedModuleIdentifier,
298 final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
299 stmt.addToNs(ImportPrefixToModuleCtx.class, impPrefix, importedModule);
300 stmt.addToNs(ImportPrefixToSemVerSourceIdentifier.class, impPrefix, semVerModuleIdentifier);
302 final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(),
303 NamespaceStatement.class);
304 stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix);
308 public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
309 if (failed.contains(imported)) {
310 throw new InferenceException(stmt.getStatementSourceReference(),
311 "Unable to find module compatible with requested import [%s(%s)].", moduleName,
312 getRequestedImportVersionString(stmt));
318 private static Optional<SemVer> getRequestedImportVersion(final StmtContext<?, ?, ?> stmt) {
319 return Optional.ofNullable(stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
322 private static String getRequestedImportVersionString(final StmtContext<?, ?, ?> stmt) {
323 return getRequestedImportVersion(stmt).map(SemVer::toString).orElse("<any>");
326 private static SemVerSourceIdentifier createSemVerModuleIdentifier(
327 final SourceIdentifier importedModuleIdentifier, final SemVer semVer) {
328 return SemVerSourceIdentifier.create(importedModuleIdentifier.getName(),
329 importedModuleIdentifier.getRevision(), semVer);