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 java.util.Objects.requireNonNull;
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;
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.QNameModule;
25 import org.opendaylight.yangtools.yang.common.Revision;
26 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
28 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.Submodule;
30 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
31 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
32 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
33 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
35 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
36 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
37 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
38 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
39 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
40 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport;
41 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.SubstatementIndexingException;
42 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
43 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
44 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
53 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
54 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
55 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
56 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
57 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
58 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
59 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
62 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
63 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
66 public final class ModuleStatementSupport
67 extends BaseStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
68 private static final @NonNull ModuleStatementSupport RFC6020_INSTANCE = new ModuleStatementSupport(
69 SubstatementValidator.builder(YangStmtMapping.MODULE)
70 .addAny(YangStmtMapping.ANYXML)
71 .addAny(YangStmtMapping.AUGMENT)
72 .addAny(YangStmtMapping.CHOICE)
73 .addOptional(YangStmtMapping.CONTACT)
74 .addAny(YangStmtMapping.CONTAINER)
75 .addOptional(YangStmtMapping.DESCRIPTION)
76 .addAny(YangStmtMapping.DEVIATION)
77 .addAny(YangStmtMapping.EXTENSION)
78 .addAny(YangStmtMapping.FEATURE)
79 .addAny(YangStmtMapping.GROUPING)
80 .addAny(YangStmtMapping.IDENTITY)
81 .addAny(YangStmtMapping.IMPORT)
82 .addAny(YangStmtMapping.INCLUDE)
83 .addAny(YangStmtMapping.LEAF)
84 .addAny(YangStmtMapping.LEAF_LIST)
85 .addAny(YangStmtMapping.LIST)
86 .addMandatory(YangStmtMapping.NAMESPACE)
87 .addAny(YangStmtMapping.NOTIFICATION)
88 .addOptional(YangStmtMapping.ORGANIZATION)
89 .addMandatory(YangStmtMapping.PREFIX)
90 .addOptional(YangStmtMapping.REFERENCE)
91 .addAny(YangStmtMapping.REVISION)
92 .addAny(YangStmtMapping.RPC)
93 .addAny(YangStmtMapping.TYPEDEF)
94 .addAny(YangStmtMapping.USES)
95 .addOptional(YangStmtMapping.YANG_VERSION)
96 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
98 private static final @NonNull ModuleStatementSupport RFC7950_INSTANCE = new ModuleStatementSupport(
99 SubstatementValidator.builder(YangStmtMapping.MODULE)
100 .addAny(YangStmtMapping.ANYDATA)
101 .addAny(YangStmtMapping.ANYXML)
102 .addAny(YangStmtMapping.AUGMENT)
103 .addAny(YangStmtMapping.CHOICE)
104 .addOptional(YangStmtMapping.CONTACT)
105 .addAny(YangStmtMapping.CONTAINER)
106 .addOptional(YangStmtMapping.DESCRIPTION)
107 .addAny(YangStmtMapping.DEVIATION)
108 .addAny(YangStmtMapping.EXTENSION)
109 .addAny(YangStmtMapping.FEATURE)
110 .addAny(YangStmtMapping.GROUPING)
111 .addAny(YangStmtMapping.IDENTITY)
112 .addAny(YangStmtMapping.IMPORT)
113 .addAny(YangStmtMapping.INCLUDE)
114 .addAny(YangStmtMapping.LEAF)
115 .addAny(YangStmtMapping.LEAF_LIST)
116 .addAny(YangStmtMapping.LIST)
117 .addMandatory(YangStmtMapping.NAMESPACE)
118 .addAny(YangStmtMapping.NOTIFICATION)
119 .addOptional(YangStmtMapping.ORGANIZATION)
120 .addMandatory(YangStmtMapping.PREFIX)
121 .addOptional(YangStmtMapping.REFERENCE)
122 .addAny(YangStmtMapping.REVISION)
123 .addAny(YangStmtMapping.RPC)
124 .addAny(YangStmtMapping.TYPEDEF)
125 .addAny(YangStmtMapping.USES)
126 .addMandatory(YangStmtMapping.YANG_VERSION)
127 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
130 private final SubstatementValidator validator;
132 private ModuleStatementSupport(final SubstatementValidator validator) {
133 super(YangStmtMapping.MODULE, CopyPolicy.REJECT);
134 this.validator = requireNonNull(validator);
137 public static @NonNull ModuleStatementSupport rfc6020Instance() {
138 return RFC6020_INSTANCE;
141 public static @NonNull ModuleStatementSupport rfc7950Instance() {
142 return RFC7950_INSTANCE;
146 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
148 return UnqualifiedQName.of(value);
149 } catch (IllegalArgumentException e) {
150 throw new SourceException(e.getMessage(), ctx, e);
155 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
156 final String moduleName = stmt.getRawArgument();
158 final URI moduleNs = SourceException.throwIfNull(
159 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
160 "Namespace of the module [%s] is missing", moduleName);
161 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
163 final String modulePrefix = SourceException.throwIfNull(
164 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
165 "Prefix of the module [%s] is missing", moduleName);
166 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
168 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
170 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
171 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
173 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
174 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
178 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
179 final URI moduleNs = SourceException.throwIfNull(
180 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
181 "Namespace of the module [%s] is missing", stmt.argument());
183 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
184 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
185 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
186 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
187 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
188 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
189 possibleDuplicateModule.sourceReference());
192 final String moduleName = stmt.getRawArgument();
193 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
195 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
196 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
197 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
199 final String modulePrefix = SourceException.throwIfNull(
200 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
201 "Prefix of the module [%s] is missing", stmt.argument());
203 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
204 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
205 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
206 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
207 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
208 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
210 if (stmt.isEnabledSemanticVersioning()) {
211 addToSemVerModuleNamespace(stmt, moduleIdentifier);
216 protected SubstatementValidator getSubstatementValidator() {
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 return new ModuleStatementImpl(ctx.getRawArgument(), ctx.getArgument(), substatements);
254 protected ModuleStatement createEmptyDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx) {
255 throw noNamespace(ctx);
259 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
260 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
261 if (substatements.isEmpty()) {
262 throw noNamespace(stmt);
265 final List<Submodule> submodules = new ArrayList<>();
266 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
267 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
268 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
269 submodules.add((Submodule) submodule);
273 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules);
274 } catch (SubstatementIndexingException e) {
275 throw new SourceException(e.getMessage(), stmt, e);
279 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
280 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.getAllFromCurrentStmtCtxNamespace(
281 IncludedSubmoduleNameToModuleCtx.class);
282 return submodules == null ? List.of() : submodules.values();
285 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
286 return new SourceException("No namespace declared in module", stmt);
289 private static void addToSemVerModuleNamespace(
290 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
291 final SourceIdentifier moduleIdentifier) {
292 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
293 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
294 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);