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.rfc7950.stmt.module;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
14 import com.google.common.annotations.Beta;
15 import com.google.common.collect.ImmutableList;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
20 import java.util.Optional;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.yangtools.openconfig.model.api.OpenConfigStatements;
23 import org.opendaylight.yangtools.yang.common.Empty;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25 import org.opendaylight.yangtools.yang.common.Revision;
26 import org.opendaylight.yangtools.yang.common.UnresolvedQName;
27 import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified;
28 import org.opendaylight.yangtools.yang.common.XMLNamespace;
29 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
30 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.Submodule;
32 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
33 import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
34 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
35 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
36 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
37 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
38 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
39 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
40 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
41 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
42 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
43 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatementDecorators;
44 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
45 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
46 import org.opendaylight.yangtools.yang.parser.api.ImportResolutionMode;
47 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
48 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
49 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
50 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
57 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
58 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
59 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
60 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
63 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
66 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
67 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
68 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
69 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
70 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
71 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
74 public final class ModuleStatementSupport
75 extends AbstractStatementSupport<Unqualified, ModuleStatement, ModuleEffectiveStatement> {
76 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
77 .addAny(YangStmtMapping.ANYXML)
78 .addAny(YangStmtMapping.AUGMENT)
79 .addAny(YangStmtMapping.CHOICE)
80 .addOptional(YangStmtMapping.CONTACT)
81 .addAny(YangStmtMapping.CONTAINER)
82 .addOptional(YangStmtMapping.DESCRIPTION)
83 .addAny(YangStmtMapping.DEVIATION)
84 .addAny(YangStmtMapping.EXTENSION)
85 .addAny(YangStmtMapping.FEATURE)
86 .addAny(YangStmtMapping.GROUPING)
87 .addAny(YangStmtMapping.IDENTITY)
88 .addAny(YangStmtMapping.IMPORT)
89 .addAny(YangStmtMapping.INCLUDE)
90 .addAny(YangStmtMapping.LEAF)
91 .addAny(YangStmtMapping.LEAF_LIST)
92 .addAny(YangStmtMapping.LIST)
93 .addMandatory(YangStmtMapping.NAMESPACE)
94 .addAny(YangStmtMapping.NOTIFICATION)
95 .addOptional(YangStmtMapping.ORGANIZATION)
96 .addMandatory(YangStmtMapping.PREFIX)
97 .addOptional(YangStmtMapping.REFERENCE)
98 .addAny(YangStmtMapping.REVISION)
99 .addAny(YangStmtMapping.RPC)
100 .addAny(YangStmtMapping.TYPEDEF)
101 .addAny(YangStmtMapping.USES)
102 .addOptional(YangStmtMapping.YANG_VERSION)
103 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
105 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
106 .addAny(YangStmtMapping.ANYDATA)
107 .addAny(YangStmtMapping.ANYXML)
108 .addAny(YangStmtMapping.AUGMENT)
109 .addAny(YangStmtMapping.CHOICE)
110 .addOptional(YangStmtMapping.CONTACT)
111 .addAny(YangStmtMapping.CONTAINER)
112 .addOptional(YangStmtMapping.DESCRIPTION)
113 .addAny(YangStmtMapping.DEVIATION)
114 .addAny(YangStmtMapping.EXTENSION)
115 .addAny(YangStmtMapping.FEATURE)
116 .addAny(YangStmtMapping.GROUPING)
117 .addAny(YangStmtMapping.IDENTITY)
118 .addAny(YangStmtMapping.IMPORT)
119 .addAny(YangStmtMapping.INCLUDE)
120 .addAny(YangStmtMapping.LEAF)
121 .addAny(YangStmtMapping.LEAF_LIST)
122 .addAny(YangStmtMapping.LIST)
123 .addMandatory(YangStmtMapping.NAMESPACE)
124 .addAny(YangStmtMapping.NOTIFICATION)
125 .addOptional(YangStmtMapping.ORGANIZATION)
126 .addMandatory(YangStmtMapping.PREFIX)
127 .addOptional(YangStmtMapping.REFERENCE)
128 .addAny(YangStmtMapping.REVISION)
129 .addAny(YangStmtMapping.RPC)
130 .addAny(YangStmtMapping.TYPEDEF)
131 .addAny(YangStmtMapping.USES)
132 .addMandatory(YangStmtMapping.YANG_VERSION)
133 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
136 private final boolean semanticVersioning;
138 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
139 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
140 semanticVersioning = config.importResolutionMode() == ImportResolutionMode.OPENCONFIG_SEMVER;
143 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
144 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
147 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
148 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
152 public Unqualified parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
154 return UnresolvedQName.unqualified(value);
155 } catch (IllegalArgumentException e) {
156 throw new SourceException(e.getMessage(), ctx, e);
161 public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
162 final String moduleName = stmt.getRawArgument();
164 final XMLNamespace moduleNs = SourceException.throwIfNull(
165 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
166 "Namespace of the module [%s] is missing", moduleName);
167 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
169 final String modulePrefix = SourceException.throwIfNull(
170 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
171 "Prefix of the module [%s] is missing", moduleName);
172 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
174 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
176 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
177 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
179 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
180 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
184 public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
185 final XMLNamespace moduleNs = SourceException.throwIfNull(
186 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
187 "Namespace of the module [%s] is missing", stmt.argument());
189 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
190 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
191 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
192 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
193 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
194 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
195 possibleDuplicateModule.sourceReference());
198 final String moduleName = stmt.getRawArgument();
199 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
201 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
202 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
203 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
205 final String modulePrefix = SourceException.throwIfNull(
206 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
207 "Prefix of the module [%s] is missing", stmt.argument());
209 stmt.addToNs(QNameModuleNamespace.class, Empty.value(), qNameModule);
210 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
211 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
212 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
213 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
214 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
215 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
217 if (semanticVersioning) {
218 addToSemVerModuleNamespace(stmt, moduleIdentifier);
223 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
224 final Current<Unqualified, ModuleStatement> stmt,
225 final List<? extends StmtContext<?, ?, ?>> substatements) {
226 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
227 super.buildEffectiveSubstatements(stmt, substatements);
228 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
229 if (submodules.isEmpty()) {
233 // Concatenate statements so they appear as if they were part of target module
234 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
235 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
236 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
237 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
238 others.add(effective);
243 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
250 protected ModuleStatement createDeclared(final BoundStmtCtx<Unqualified> ctx,
251 final ImmutableList<DeclaredStatement<?>> substatements) {
252 if (substatements.isEmpty()) {
253 throw noNamespace(ctx);
255 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
259 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
260 final DeclarationReference reference) {
261 return DeclaredStatementDecorators.decorateModule(stmt, reference);
265 protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
266 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
267 if (substatements.isEmpty()) {
268 throw noNamespace(stmt);
271 final List<Submodule> submodules = new ArrayList<>();
272 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
273 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
274 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
275 submodules.add((Submodule) submodule);
278 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class, Empty.value()));
280 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
281 } catch (SubstatementIndexingException e) {
282 throw new SourceException(e.getMessage(), stmt, e);
286 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
287 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
288 IncludedSubmoduleNameToModuleCtx.class);
289 return submodules == null ? List.of() : submodules.values();
292 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
293 return new SourceException("No namespace declared in module", stmt);
296 private static void addToSemVerModuleNamespace(
297 final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt,
298 final SourceIdentifier moduleIdentifier) {
299 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
300 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
301 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);