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.model.ri.stmt.DeclaredStatements;
43 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
44 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
45 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
46 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
56 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
57 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
58 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
59 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
65 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
66 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
69 public final class ModuleStatementSupport
70 extends AbstractStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
71 private static final @NonNull ModuleStatementSupport RFC6020_INSTANCE = new ModuleStatementSupport(
72 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 @NonNull ModuleStatementSupport RFC7950_INSTANCE = new ModuleStatementSupport(
102 SubstatementValidator.builder(YangStmtMapping.MODULE)
103 .addAny(YangStmtMapping.ANYDATA)
104 .addAny(YangStmtMapping.ANYXML)
105 .addAny(YangStmtMapping.AUGMENT)
106 .addAny(YangStmtMapping.CHOICE)
107 .addOptional(YangStmtMapping.CONTACT)
108 .addAny(YangStmtMapping.CONTAINER)
109 .addOptional(YangStmtMapping.DESCRIPTION)
110 .addAny(YangStmtMapping.DEVIATION)
111 .addAny(YangStmtMapping.EXTENSION)
112 .addAny(YangStmtMapping.FEATURE)
113 .addAny(YangStmtMapping.GROUPING)
114 .addAny(YangStmtMapping.IDENTITY)
115 .addAny(YangStmtMapping.IMPORT)
116 .addAny(YangStmtMapping.INCLUDE)
117 .addAny(YangStmtMapping.LEAF)
118 .addAny(YangStmtMapping.LEAF_LIST)
119 .addAny(YangStmtMapping.LIST)
120 .addMandatory(YangStmtMapping.NAMESPACE)
121 .addAny(YangStmtMapping.NOTIFICATION)
122 .addOptional(YangStmtMapping.ORGANIZATION)
123 .addMandatory(YangStmtMapping.PREFIX)
124 .addOptional(YangStmtMapping.REFERENCE)
125 .addAny(YangStmtMapping.REVISION)
126 .addAny(YangStmtMapping.RPC)
127 .addAny(YangStmtMapping.TYPEDEF)
128 .addAny(YangStmtMapping.USES)
129 .addMandatory(YangStmtMapping.YANG_VERSION)
130 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
133 private final SubstatementValidator validator;
135 private ModuleStatementSupport(final SubstatementValidator validator) {
136 super(YangStmtMapping.MODULE, StatementPolicy.reject());
137 this.validator = requireNonNull(validator);
140 public static @NonNull ModuleStatementSupport rfc6020Instance() {
141 return RFC6020_INSTANCE;
144 public static @NonNull ModuleStatementSupport rfc7950Instance() {
145 return RFC7950_INSTANCE;
149 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
151 return UnqualifiedQName.of(value);
152 } catch (IllegalArgumentException e) {
153 throw new SourceException(e.getMessage(), ctx, e);
158 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
159 final String moduleName = stmt.getRawArgument();
161 final XMLNamespace moduleNs = SourceException.throwIfNull(
162 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
163 "Namespace of the module [%s] is missing", moduleName);
164 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
166 final String modulePrefix = SourceException.throwIfNull(
167 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
168 "Prefix of the module [%s] is missing", moduleName);
169 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
171 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
173 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
174 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
176 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
177 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
181 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
182 final XMLNamespace moduleNs = SourceException.throwIfNull(
183 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
184 "Namespace of the module [%s] is missing", stmt.argument());
186 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
187 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
188 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
189 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
190 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
191 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
192 possibleDuplicateModule.sourceReference());
195 final String moduleName = stmt.getRawArgument();
196 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
198 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
199 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
200 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
202 final String modulePrefix = SourceException.throwIfNull(
203 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
204 "Prefix of the module [%s] is missing", stmt.argument());
206 stmt.addToNs(QNameModuleNamespace.class, Empty.getInstance(), qNameModule);
207 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
208 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
209 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
210 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
211 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
212 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
214 if (stmt.isEnabledSemanticVersioning()) {
215 addToSemVerModuleNamespace(stmt, moduleIdentifier);
220 protected SubstatementValidator getSubstatementValidator() {
225 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
226 final Current<UnqualifiedQName, ModuleStatement> stmt,
227 final List<? extends StmtContext<?, ?, ?>> substatements) {
228 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
229 super.buildEffectiveSubstatements(stmt, substatements);
230 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
231 if (submodules.isEmpty()) {
235 // Concatenate statements so they appear as if they were part of target module
236 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
237 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
238 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
239 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
240 others.add(effective);
245 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
252 protected ModuleStatement createDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx,
253 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
254 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
258 protected ModuleStatement createEmptyDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx) {
259 throw noNamespace(ctx);
263 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
264 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
265 if (substatements.isEmpty()) {
266 throw noNamespace(stmt);
269 final List<Submodule> submodules = new ArrayList<>();
270 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
271 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
272 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
273 submodules.add((Submodule) submodule);
276 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
277 Empty.getInstance()));
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<UnqualifiedQName, 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);