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.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.parser.api.YangParserConfiguration;
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.DeclaredStatements;
44 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
45 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
46 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
47 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
57 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
58 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
59 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
66 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
67 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
70 public final class ModuleStatementSupport
71 extends AbstractStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
72 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
73 .addAny(YangStmtMapping.ANYXML)
74 .addAny(YangStmtMapping.AUGMENT)
75 .addAny(YangStmtMapping.CHOICE)
76 .addOptional(YangStmtMapping.CONTACT)
77 .addAny(YangStmtMapping.CONTAINER)
78 .addOptional(YangStmtMapping.DESCRIPTION)
79 .addAny(YangStmtMapping.DEVIATION)
80 .addAny(YangStmtMapping.EXTENSION)
81 .addAny(YangStmtMapping.FEATURE)
82 .addAny(YangStmtMapping.GROUPING)
83 .addAny(YangStmtMapping.IDENTITY)
84 .addAny(YangStmtMapping.IMPORT)
85 .addAny(YangStmtMapping.INCLUDE)
86 .addAny(YangStmtMapping.LEAF)
87 .addAny(YangStmtMapping.LEAF_LIST)
88 .addAny(YangStmtMapping.LIST)
89 .addMandatory(YangStmtMapping.NAMESPACE)
90 .addAny(YangStmtMapping.NOTIFICATION)
91 .addOptional(YangStmtMapping.ORGANIZATION)
92 .addMandatory(YangStmtMapping.PREFIX)
93 .addOptional(YangStmtMapping.REFERENCE)
94 .addAny(YangStmtMapping.REVISION)
95 .addAny(YangStmtMapping.RPC)
96 .addAny(YangStmtMapping.TYPEDEF)
97 .addAny(YangStmtMapping.USES)
98 .addOptional(YangStmtMapping.YANG_VERSION)
99 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
101 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
102 .addAny(YangStmtMapping.ANYDATA)
103 .addAny(YangStmtMapping.ANYXML)
104 .addAny(YangStmtMapping.AUGMENT)
105 .addAny(YangStmtMapping.CHOICE)
106 .addOptional(YangStmtMapping.CONTACT)
107 .addAny(YangStmtMapping.CONTAINER)
108 .addOptional(YangStmtMapping.DESCRIPTION)
109 .addAny(YangStmtMapping.DEVIATION)
110 .addAny(YangStmtMapping.EXTENSION)
111 .addAny(YangStmtMapping.FEATURE)
112 .addAny(YangStmtMapping.GROUPING)
113 .addAny(YangStmtMapping.IDENTITY)
114 .addAny(YangStmtMapping.IMPORT)
115 .addAny(YangStmtMapping.INCLUDE)
116 .addAny(YangStmtMapping.LEAF)
117 .addAny(YangStmtMapping.LEAF_LIST)
118 .addAny(YangStmtMapping.LIST)
119 .addMandatory(YangStmtMapping.NAMESPACE)
120 .addAny(YangStmtMapping.NOTIFICATION)
121 .addOptional(YangStmtMapping.ORGANIZATION)
122 .addMandatory(YangStmtMapping.PREFIX)
123 .addOptional(YangStmtMapping.REFERENCE)
124 .addAny(YangStmtMapping.REVISION)
125 .addAny(YangStmtMapping.RPC)
126 .addAny(YangStmtMapping.TYPEDEF)
127 .addAny(YangStmtMapping.USES)
128 .addMandatory(YangStmtMapping.YANG_VERSION)
129 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
132 private final SubstatementValidator validator;
134 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
135 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config);
136 this.validator = requireNonNull(validator);
139 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
140 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
143 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
144 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
148 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
150 return UnqualifiedQName.of(value);
151 } catch (IllegalArgumentException e) {
152 throw new SourceException(e.getMessage(), ctx, e);
157 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
158 final String moduleName = stmt.getRawArgument();
160 final XMLNamespace moduleNs = SourceException.throwIfNull(
161 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
162 "Namespace of the module [%s] is missing", moduleName);
163 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
165 final String modulePrefix = SourceException.throwIfNull(
166 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
167 "Prefix of the module [%s] is missing", moduleName);
168 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
170 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
172 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
173 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
175 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
176 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
180 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
181 final XMLNamespace moduleNs = SourceException.throwIfNull(
182 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
183 "Namespace of the module [%s] is missing", stmt.argument());
185 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
186 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
187 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
188 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
189 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
190 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
191 possibleDuplicateModule.sourceReference());
194 final String moduleName = stmt.getRawArgument();
195 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
197 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
198 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
199 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
201 final String modulePrefix = SourceException.throwIfNull(
202 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
203 "Prefix of the module [%s] is missing", stmt.argument());
205 stmt.addToNs(QNameModuleNamespace.class, Empty.getInstance(), qNameModule);
206 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
207 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
208 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
209 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
210 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
211 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
213 if (stmt.isEnabledSemanticVersioning()) {
214 addToSemVerModuleNamespace(stmt, moduleIdentifier);
219 protected SubstatementValidator getSubstatementValidator() {
224 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
225 final Current<UnqualifiedQName, ModuleStatement> stmt,
226 final List<? extends StmtContext<?, ?, ?>> substatements) {
227 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
228 super.buildEffectiveSubstatements(stmt, substatements);
229 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
230 if (submodules.isEmpty()) {
234 // Concatenate statements so they appear as if they were part of target module
235 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
236 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
237 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
238 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
239 others.add(effective);
244 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
251 protected ModuleStatement createDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx,
252 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
253 if (substatements.isEmpty()) {
254 throw noNamespace(ctx);
256 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
260 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
261 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
262 if (substatements.isEmpty()) {
263 throw noNamespace(stmt);
266 final List<Submodule> submodules = new ArrayList<>();
267 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
268 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
269 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
270 submodules.add((Submodule) submodule);
273 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
274 Empty.getInstance()));
276 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
277 } catch (SubstatementIndexingException e) {
278 throw new SourceException(e.getMessage(), stmt, e);
282 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
283 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
284 IncludedSubmoduleNameToModuleCtx.class);
285 return submodules == null ? List.of() : submodules.values();
288 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
289 return new SourceException("No namespace declared in module", stmt);
292 private static void addToSemVerModuleNamespace(
293 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
294 final SourceIdentifier moduleIdentifier) {
295 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
296 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
297 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);