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.UnqualifiedQName;
27 import org.opendaylight.yangtools.yang.common.XMLNamespace;
28 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
29 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.Submodule;
31 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
32 import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
33 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
34 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
35 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
36 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
37 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
38 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
39 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
40 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
41 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
42 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatementDecorators;
43 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
44 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
45 import org.opendaylight.yangtools.yang.parser.api.ImportResolutionMode;
46 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
47 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
48 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
49 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
57 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
58 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
59 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
61 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
66 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
67 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
68 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
69 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
72 public final class ModuleStatementSupport
73 extends AbstractStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
74 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
75 .addAny(YangStmtMapping.ANYXML)
76 .addAny(YangStmtMapping.AUGMENT)
77 .addAny(YangStmtMapping.CHOICE)
78 .addOptional(YangStmtMapping.CONTACT)
79 .addAny(YangStmtMapping.CONTAINER)
80 .addOptional(YangStmtMapping.DESCRIPTION)
81 .addAny(YangStmtMapping.DEVIATION)
82 .addAny(YangStmtMapping.EXTENSION)
83 .addAny(YangStmtMapping.FEATURE)
84 .addAny(YangStmtMapping.GROUPING)
85 .addAny(YangStmtMapping.IDENTITY)
86 .addAny(YangStmtMapping.IMPORT)
87 .addAny(YangStmtMapping.INCLUDE)
88 .addAny(YangStmtMapping.LEAF)
89 .addAny(YangStmtMapping.LEAF_LIST)
90 .addAny(YangStmtMapping.LIST)
91 .addMandatory(YangStmtMapping.NAMESPACE)
92 .addAny(YangStmtMapping.NOTIFICATION)
93 .addOptional(YangStmtMapping.ORGANIZATION)
94 .addMandatory(YangStmtMapping.PREFIX)
95 .addOptional(YangStmtMapping.REFERENCE)
96 .addAny(YangStmtMapping.REVISION)
97 .addAny(YangStmtMapping.RPC)
98 .addAny(YangStmtMapping.TYPEDEF)
99 .addAny(YangStmtMapping.USES)
100 .addOptional(YangStmtMapping.YANG_VERSION)
101 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
103 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
104 .addAny(YangStmtMapping.ANYDATA)
105 .addAny(YangStmtMapping.ANYXML)
106 .addAny(YangStmtMapping.AUGMENT)
107 .addAny(YangStmtMapping.CHOICE)
108 .addOptional(YangStmtMapping.CONTACT)
109 .addAny(YangStmtMapping.CONTAINER)
110 .addOptional(YangStmtMapping.DESCRIPTION)
111 .addAny(YangStmtMapping.DEVIATION)
112 .addAny(YangStmtMapping.EXTENSION)
113 .addAny(YangStmtMapping.FEATURE)
114 .addAny(YangStmtMapping.GROUPING)
115 .addAny(YangStmtMapping.IDENTITY)
116 .addAny(YangStmtMapping.IMPORT)
117 .addAny(YangStmtMapping.INCLUDE)
118 .addAny(YangStmtMapping.LEAF)
119 .addAny(YangStmtMapping.LEAF_LIST)
120 .addAny(YangStmtMapping.LIST)
121 .addMandatory(YangStmtMapping.NAMESPACE)
122 .addAny(YangStmtMapping.NOTIFICATION)
123 .addOptional(YangStmtMapping.ORGANIZATION)
124 .addMandatory(YangStmtMapping.PREFIX)
125 .addOptional(YangStmtMapping.REFERENCE)
126 .addAny(YangStmtMapping.REVISION)
127 .addAny(YangStmtMapping.RPC)
128 .addAny(YangStmtMapping.TYPEDEF)
129 .addAny(YangStmtMapping.USES)
130 .addMandatory(YangStmtMapping.YANG_VERSION)
131 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
134 private final boolean semanticVersioning;
136 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
137 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
138 semanticVersioning = config.importResolutionMode() == ImportResolutionMode.OPENCONFIG_SEMVER;
141 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
142 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
145 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
146 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
150 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
152 return UnqualifiedQName.of(value);
153 } catch (IllegalArgumentException e) {
154 throw new SourceException(e.getMessage(), ctx, e);
159 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
160 final String moduleName = stmt.getRawArgument();
162 final XMLNamespace moduleNs = SourceException.throwIfNull(
163 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
164 "Namespace of the module [%s] is missing", moduleName);
165 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
167 final String modulePrefix = SourceException.throwIfNull(
168 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
169 "Prefix of the module [%s] is missing", moduleName);
170 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
172 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
174 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
175 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
177 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
178 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
182 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
183 final XMLNamespace moduleNs = SourceException.throwIfNull(
184 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
185 "Namespace of the module [%s] is missing", stmt.argument());
187 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
188 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
189 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
190 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
191 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
192 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
193 possibleDuplicateModule.sourceReference());
196 final String moduleName = stmt.getRawArgument();
197 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
199 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
200 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
201 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
203 final String modulePrefix = SourceException.throwIfNull(
204 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
205 "Prefix of the module [%s] is missing", stmt.argument());
207 stmt.addToNs(QNameModuleNamespace.class, Empty.getInstance(), qNameModule);
208 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
209 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
210 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
211 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
212 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
213 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
215 if (semanticVersioning) {
216 addToSemVerModuleNamespace(stmt, moduleIdentifier);
221 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
222 final Current<UnqualifiedQName, ModuleStatement> stmt,
223 final List<? extends StmtContext<?, ?, ?>> substatements) {
224 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
225 super.buildEffectiveSubstatements(stmt, substatements);
226 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
227 if (submodules.isEmpty()) {
231 // Concatenate statements so they appear as if they were part of target module
232 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
233 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
234 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
235 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
236 others.add(effective);
241 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
248 protected ModuleStatement createDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx,
249 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
250 if (substatements.isEmpty()) {
251 throw noNamespace(ctx);
253 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
257 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
258 final DeclarationReference reference) {
259 return DeclaredStatementDecorators.decorateModule(stmt, reference);
263 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
264 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
265 if (substatements.isEmpty()) {
266 throw noNamespace(stmt);
269 final List<Submodule> submodules = new ArrayList<>();
270 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
271 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
272 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
273 submodules.add((Submodule) submodule);
276 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
277 Empty.getInstance()));
279 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
280 } catch (SubstatementIndexingException e) {
281 throw new SourceException(e.getMessage(), stmt, e);
285 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
286 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
287 IncludedSubmoduleNameToModuleCtx.class);
288 return submodules == null ? List.of() : submodules.values();
291 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
292 return new SourceException("No namespace declared in module", stmt);
295 private static void addToSemVerModuleNamespace(
296 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
297 final SourceIdentifier moduleIdentifier) {
298 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
299 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
300 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);