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.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.parser.rfc7950.stmt.SubstatementIndexingException;
43 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
44 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
45 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
55 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
56 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
57 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
58 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
59 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
64 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
65 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
68 public final class ModuleStatementSupport
69 extends AbstractStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
70 private static final @NonNull ModuleStatementSupport RFC6020_INSTANCE = new ModuleStatementSupport(
71 SubstatementValidator.builder(YangStmtMapping.MODULE)
72 .addAny(YangStmtMapping.ANYXML)
73 .addAny(YangStmtMapping.AUGMENT)
74 .addAny(YangStmtMapping.CHOICE)
75 .addOptional(YangStmtMapping.CONTACT)
76 .addAny(YangStmtMapping.CONTAINER)
77 .addOptional(YangStmtMapping.DESCRIPTION)
78 .addAny(YangStmtMapping.DEVIATION)
79 .addAny(YangStmtMapping.EXTENSION)
80 .addAny(YangStmtMapping.FEATURE)
81 .addAny(YangStmtMapping.GROUPING)
82 .addAny(YangStmtMapping.IDENTITY)
83 .addAny(YangStmtMapping.IMPORT)
84 .addAny(YangStmtMapping.INCLUDE)
85 .addAny(YangStmtMapping.LEAF)
86 .addAny(YangStmtMapping.LEAF_LIST)
87 .addAny(YangStmtMapping.LIST)
88 .addMandatory(YangStmtMapping.NAMESPACE)
89 .addAny(YangStmtMapping.NOTIFICATION)
90 .addOptional(YangStmtMapping.ORGANIZATION)
91 .addMandatory(YangStmtMapping.PREFIX)
92 .addOptional(YangStmtMapping.REFERENCE)
93 .addAny(YangStmtMapping.REVISION)
94 .addAny(YangStmtMapping.RPC)
95 .addAny(YangStmtMapping.TYPEDEF)
96 .addAny(YangStmtMapping.USES)
97 .addOptional(YangStmtMapping.YANG_VERSION)
98 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
100 private static final @NonNull ModuleStatementSupport RFC7950_INSTANCE = new ModuleStatementSupport(
101 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 SubstatementValidator validator) {
135 super(YangStmtMapping.MODULE, StatementPolicy.reject());
136 this.validator = requireNonNull(validator);
139 public static @NonNull ModuleStatementSupport rfc6020Instance() {
140 return RFC6020_INSTANCE;
143 public static @NonNull ModuleStatementSupport rfc7950Instance() {
144 return RFC7950_INSTANCE;
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 return new ModuleStatementImpl(ctx.getRawArgument(), ctx.getArgument(), substatements);
257 protected ModuleStatement createEmptyDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx) {
258 throw noNamespace(ctx);
262 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
263 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
264 if (substatements.isEmpty()) {
265 throw noNamespace(stmt);
268 final List<Submodule> submodules = new ArrayList<>();
269 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
270 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
271 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
272 submodules.add((Submodule) submodule);
275 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
276 Empty.getInstance()));
278 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
279 } catch (SubstatementIndexingException e) {
280 throw new SourceException(e.getMessage(), stmt, e);
284 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
285 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
286 IncludedSubmoduleNameToModuleCtx.class);
287 return submodules == null ? List.of() : submodules.values();
290 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
291 return new SourceException("No namespace declared in module", stmt);
294 private static void addToSemVerModuleNamespace(
295 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
296 final SourceIdentifier moduleIdentifier) {
297 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
298 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
299 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);