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.CommonStmtCtx;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
57 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
58 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
59 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
62 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
66 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
67 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
68 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
69 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
70 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
73 public final class ModuleStatementSupport
74 extends AbstractStatementSupport<Unqualified, ModuleStatement, ModuleEffectiveStatement> {
75 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
76 .addAny(YangStmtMapping.ANYXML)
77 .addAny(YangStmtMapping.AUGMENT)
78 .addAny(YangStmtMapping.CHOICE)
79 .addOptional(YangStmtMapping.CONTACT)
80 .addAny(YangStmtMapping.CONTAINER)
81 .addOptional(YangStmtMapping.DESCRIPTION)
82 .addAny(YangStmtMapping.DEVIATION)
83 .addAny(YangStmtMapping.EXTENSION)
84 .addAny(YangStmtMapping.FEATURE)
85 .addAny(YangStmtMapping.GROUPING)
86 .addAny(YangStmtMapping.IDENTITY)
87 .addAny(YangStmtMapping.IMPORT)
88 .addAny(YangStmtMapping.INCLUDE)
89 .addAny(YangStmtMapping.LEAF)
90 .addAny(YangStmtMapping.LEAF_LIST)
91 .addAny(YangStmtMapping.LIST)
92 .addMandatory(YangStmtMapping.NAMESPACE)
93 .addAny(YangStmtMapping.NOTIFICATION)
94 .addOptional(YangStmtMapping.ORGANIZATION)
95 .addMandatory(YangStmtMapping.PREFIX)
96 .addOptional(YangStmtMapping.REFERENCE)
97 .addAny(YangStmtMapping.REVISION)
98 .addAny(YangStmtMapping.RPC)
99 .addAny(YangStmtMapping.TYPEDEF)
100 .addAny(YangStmtMapping.USES)
101 .addOptional(YangStmtMapping.YANG_VERSION)
102 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
104 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
105 .addAny(YangStmtMapping.ANYDATA)
106 .addAny(YangStmtMapping.ANYXML)
107 .addAny(YangStmtMapping.AUGMENT)
108 .addAny(YangStmtMapping.CHOICE)
109 .addOptional(YangStmtMapping.CONTACT)
110 .addAny(YangStmtMapping.CONTAINER)
111 .addOptional(YangStmtMapping.DESCRIPTION)
112 .addAny(YangStmtMapping.DEVIATION)
113 .addAny(YangStmtMapping.EXTENSION)
114 .addAny(YangStmtMapping.FEATURE)
115 .addAny(YangStmtMapping.GROUPING)
116 .addAny(YangStmtMapping.IDENTITY)
117 .addAny(YangStmtMapping.IMPORT)
118 .addAny(YangStmtMapping.INCLUDE)
119 .addAny(YangStmtMapping.LEAF)
120 .addAny(YangStmtMapping.LEAF_LIST)
121 .addAny(YangStmtMapping.LIST)
122 .addMandatory(YangStmtMapping.NAMESPACE)
123 .addAny(YangStmtMapping.NOTIFICATION)
124 .addOptional(YangStmtMapping.ORGANIZATION)
125 .addMandatory(YangStmtMapping.PREFIX)
126 .addOptional(YangStmtMapping.REFERENCE)
127 .addAny(YangStmtMapping.REVISION)
128 .addAny(YangStmtMapping.RPC)
129 .addAny(YangStmtMapping.TYPEDEF)
130 .addAny(YangStmtMapping.USES)
131 .addMandatory(YangStmtMapping.YANG_VERSION)
132 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
135 private final boolean semanticVersioning;
137 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
138 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
139 semanticVersioning = config.importResolutionMode() == ImportResolutionMode.OPENCONFIG_SEMVER;
142 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
143 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
146 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
147 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
151 public Unqualified parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
153 return UnresolvedQName.unqualified(value);
154 } catch (IllegalArgumentException e) {
155 throw new SourceException(e.getMessage(), ctx, e);
160 public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
161 final String moduleName = stmt.getRawArgument();
163 final XMLNamespace moduleNs = SourceException.throwIfNull(
164 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
165 "Namespace of the module [%s] is missing", moduleName);
166 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
168 final String modulePrefix = SourceException.throwIfNull(
169 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
170 "Prefix of the module [%s] is missing", moduleName);
171 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
173 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
175 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
176 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
178 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
179 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
183 public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
184 final XMLNamespace moduleNs = SourceException.throwIfNull(
185 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
186 "Namespace of the module [%s] is missing", stmt.argument());
188 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
189 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
190 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
191 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
192 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
193 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
194 possibleDuplicateModule.sourceReference());
197 final String moduleName = stmt.getRawArgument();
198 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
200 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
201 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
202 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
204 final String modulePrefix = SourceException.throwIfNull(
205 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
206 "Prefix of the module [%s] is missing", stmt.argument());
208 stmt.addToNs(QNameModuleNamespace.class, Empty.value(), qNameModule);
209 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
210 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
211 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
212 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
213 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
214 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
216 if (semanticVersioning) {
217 addToSemVerModuleNamespace(stmt, moduleIdentifier);
222 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
223 final Current<Unqualified, ModuleStatement> stmt,
224 final List<? extends StmtContext<?, ?, ?>> substatements) {
225 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
226 super.buildEffectiveSubstatements(stmt, substatements);
227 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
228 if (submodules.isEmpty()) {
232 // Concatenate statements so they appear as if they were part of target module
233 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
234 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
235 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
236 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
237 others.add(effective);
242 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
249 protected ModuleStatement createDeclared(final StmtContext<Unqualified, ModuleStatement, ?> ctx,
250 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
251 if (substatements.isEmpty()) {
252 throw noNamespace(ctx);
254 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
258 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
259 final DeclarationReference reference) {
260 return DeclaredStatementDecorators.decorateModule(stmt, reference);
264 protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
265 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
266 if (substatements.isEmpty()) {
267 throw noNamespace(stmt);
270 final List<Submodule> submodules = new ArrayList<>();
271 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
272 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
273 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
274 submodules.add((Submodule) submodule);
277 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class, Empty.value()));
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<Unqualified, 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);