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 java.util.Objects.requireNonNull;
13 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
15 import com.google.common.annotations.Beta;
16 import com.google.common.collect.ImmutableList;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.List;
21 import java.util.Optional;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.opendaylight.yangtools.openconfig.model.api.OpenConfigStatements;
24 import org.opendaylight.yangtools.yang.common.Empty;
25 import org.opendaylight.yangtools.yang.common.QNameModule;
26 import org.opendaylight.yangtools.yang.common.Revision;
27 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
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<UnqualifiedQName, 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 SubstatementValidator validator;
136 private final boolean semanticVersioning;
138 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
139 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config);
140 this.validator = requireNonNull(validator);
141 semanticVersioning = config.importResolutionMode() == ImportResolutionMode.OPENCONFIG_SEMVER;
144 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
145 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
148 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
149 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
153 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
155 return UnqualifiedQName.of(value);
156 } catch (IllegalArgumentException e) {
157 throw new SourceException(e.getMessage(), ctx, e);
162 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
163 final String moduleName = stmt.getRawArgument();
165 final XMLNamespace moduleNs = SourceException.throwIfNull(
166 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
167 "Namespace of the module [%s] is missing", moduleName);
168 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
170 final String modulePrefix = SourceException.throwIfNull(
171 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
172 "Prefix of the module [%s] is missing", moduleName);
173 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
175 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
177 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
178 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
180 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
181 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
185 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
186 final XMLNamespace moduleNs = SourceException.throwIfNull(
187 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
188 "Namespace of the module [%s] is missing", stmt.argument());
190 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
191 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
192 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
193 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
194 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
195 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
196 possibleDuplicateModule.sourceReference());
199 final String moduleName = stmt.getRawArgument();
200 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
202 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
203 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
204 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
206 final String modulePrefix = SourceException.throwIfNull(
207 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
208 "Prefix of the module [%s] is missing", stmt.argument());
210 stmt.addToNs(QNameModuleNamespace.class, Empty.getInstance(), qNameModule);
211 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
212 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
213 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
214 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
215 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
216 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
218 if (semanticVersioning) {
219 addToSemVerModuleNamespace(stmt, moduleIdentifier);
224 protected SubstatementValidator getSubstatementValidator() {
229 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
230 final Current<UnqualifiedQName, ModuleStatement> stmt,
231 final List<? extends StmtContext<?, ?, ?>> substatements) {
232 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
233 super.buildEffectiveSubstatements(stmt, substatements);
234 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
235 if (submodules.isEmpty()) {
239 // Concatenate statements so they appear as if they were part of target module
240 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
241 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
242 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
243 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
244 others.add(effective);
249 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
256 protected ModuleStatement createDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx,
257 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
258 if (substatements.isEmpty()) {
259 throw noNamespace(ctx);
261 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
265 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
266 final DeclarationReference reference) {
267 return DeclaredStatementDecorators.decorateModule(stmt, reference);
271 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
272 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
273 if (substatements.isEmpty()) {
274 throw noNamespace(stmt);
277 final List<Submodule> submodules = new ArrayList<>();
278 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
279 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
280 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
281 submodules.add((Submodule) submodule);
284 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
285 Empty.getInstance()));
287 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
288 } catch (SubstatementIndexingException e) {
289 throw new SourceException(e.getMessage(), stmt, e);
293 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
294 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
295 IncludedSubmoduleNameToModuleCtx.class);
296 return submodules == null ? List.of() : submodules.values();
299 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
300 return new SourceException("No namespace declared in module", stmt);
303 private static void addToSemVerModuleNamespace(
304 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
305 final SourceIdentifier moduleIdentifier) {
306 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
307 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
308 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);