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.YangParserConfiguration;
47 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
48 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
49 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
57 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
58 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
59 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
61 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
66 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
67 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
68 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
69 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
72 public final class ModuleStatementSupport
73 extends AbstractStatementSupport<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> {
74 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
75 .addAny(YangStmtMapping.ANYXML)
76 .addAny(YangStmtMapping.AUGMENT)
77 .addAny(YangStmtMapping.CHOICE)
78 .addOptional(YangStmtMapping.CONTACT)
79 .addAny(YangStmtMapping.CONTAINER)
80 .addOptional(YangStmtMapping.DESCRIPTION)
81 .addAny(YangStmtMapping.DEVIATION)
82 .addAny(YangStmtMapping.EXTENSION)
83 .addAny(YangStmtMapping.FEATURE)
84 .addAny(YangStmtMapping.GROUPING)
85 .addAny(YangStmtMapping.IDENTITY)
86 .addAny(YangStmtMapping.IMPORT)
87 .addAny(YangStmtMapping.INCLUDE)
88 .addAny(YangStmtMapping.LEAF)
89 .addAny(YangStmtMapping.LEAF_LIST)
90 .addAny(YangStmtMapping.LIST)
91 .addMandatory(YangStmtMapping.NAMESPACE)
92 .addAny(YangStmtMapping.NOTIFICATION)
93 .addOptional(YangStmtMapping.ORGANIZATION)
94 .addMandatory(YangStmtMapping.PREFIX)
95 .addOptional(YangStmtMapping.REFERENCE)
96 .addAny(YangStmtMapping.REVISION)
97 .addAny(YangStmtMapping.RPC)
98 .addAny(YangStmtMapping.TYPEDEF)
99 .addAny(YangStmtMapping.USES)
100 .addOptional(YangStmtMapping.YANG_VERSION)
101 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
103 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
104 .addAny(YangStmtMapping.ANYDATA)
105 .addAny(YangStmtMapping.ANYXML)
106 .addAny(YangStmtMapping.AUGMENT)
107 .addAny(YangStmtMapping.CHOICE)
108 .addOptional(YangStmtMapping.CONTACT)
109 .addAny(YangStmtMapping.CONTAINER)
110 .addOptional(YangStmtMapping.DESCRIPTION)
111 .addAny(YangStmtMapping.DEVIATION)
112 .addAny(YangStmtMapping.EXTENSION)
113 .addAny(YangStmtMapping.FEATURE)
114 .addAny(YangStmtMapping.GROUPING)
115 .addAny(YangStmtMapping.IDENTITY)
116 .addAny(YangStmtMapping.IMPORT)
117 .addAny(YangStmtMapping.INCLUDE)
118 .addAny(YangStmtMapping.LEAF)
119 .addAny(YangStmtMapping.LEAF_LIST)
120 .addAny(YangStmtMapping.LIST)
121 .addMandatory(YangStmtMapping.NAMESPACE)
122 .addAny(YangStmtMapping.NOTIFICATION)
123 .addOptional(YangStmtMapping.ORGANIZATION)
124 .addMandatory(YangStmtMapping.PREFIX)
125 .addOptional(YangStmtMapping.REFERENCE)
126 .addAny(YangStmtMapping.REVISION)
127 .addAny(YangStmtMapping.RPC)
128 .addAny(YangStmtMapping.TYPEDEF)
129 .addAny(YangStmtMapping.USES)
130 .addMandatory(YangStmtMapping.YANG_VERSION)
131 .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
134 private final SubstatementValidator validator;
136 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
137 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config);
138 this.validator = requireNonNull(validator);
141 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
142 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
145 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
146 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
150 public UnqualifiedQName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
152 return UnqualifiedQName.of(value);
153 } catch (IllegalArgumentException e) {
154 throw new SourceException(e.getMessage(), ctx, e);
159 public void onPreLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
160 final String moduleName = stmt.getRawArgument();
162 final XMLNamespace moduleNs = SourceException.throwIfNull(
163 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
164 "Namespace of the module [%s] is missing", moduleName);
165 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
167 final String modulePrefix = SourceException.throwIfNull(
168 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
169 "Prefix of the module [%s] is missing", moduleName);
170 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
172 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
174 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
175 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
177 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
178 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
182 public void onLinkageDeclared(final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt) {
183 final XMLNamespace moduleNs = SourceException.throwIfNull(
184 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
185 "Namespace of the module [%s] is missing", stmt.argument());
187 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
188 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
189 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
190 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
191 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
192 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
193 possibleDuplicateModule.sourceReference());
196 final String moduleName = stmt.getRawArgument();
197 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
199 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
200 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
201 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
203 final String modulePrefix = SourceException.throwIfNull(
204 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
205 "Prefix of the module [%s] is missing", stmt.argument());
207 stmt.addToNs(QNameModuleNamespace.class, Empty.getInstance(), qNameModule);
208 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
209 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
210 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
211 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
212 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
213 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
215 if (stmt.isEnabledSemanticVersioning()) {
216 addToSemVerModuleNamespace(stmt, moduleIdentifier);
221 protected SubstatementValidator getSubstatementValidator() {
226 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
227 final Current<UnqualifiedQName, ModuleStatement> stmt,
228 final List<? extends StmtContext<?, ?, ?>> substatements) {
229 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
230 super.buildEffectiveSubstatements(stmt, substatements);
231 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
232 if (submodules.isEmpty()) {
236 // Concatenate statements so they appear as if they were part of target module
237 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
238 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
239 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
240 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
241 others.add(effective);
246 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
253 protected ModuleStatement createDeclared(final StmtContext<UnqualifiedQName, ModuleStatement, ?> ctx,
254 final ImmutableList<? extends DeclaredStatement<?>> substatements) {
255 if (substatements.isEmpty()) {
256 throw noNamespace(ctx);
258 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
262 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
263 final DeclarationReference reference) {
264 return DeclaredStatementDecorators.decorateModule(stmt, reference);
268 protected ModuleEffectiveStatement createEffective(final Current<UnqualifiedQName, ModuleStatement> stmt,
269 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
270 if (substatements.isEmpty()) {
271 throw noNamespace(stmt);
274 final List<Submodule> submodules = new ArrayList<>();
275 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
276 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
277 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
278 submodules.add((Submodule) submodule);
281 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class,
282 Empty.getInstance()));
284 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
285 } catch (SubstatementIndexingException e) {
286 throw new SourceException(e.getMessage(), stmt, e);
290 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
291 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
292 IncludedSubmoduleNameToModuleCtx.class);
293 return submodules == null ? List.of() : submodules.values();
296 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
297 return new SourceException("No namespace declared in module", stmt);
300 private static void addToSemVerModuleNamespace(
301 final Mutable<UnqualifiedQName, ModuleStatement, ModuleEffectiveStatement> stmt,
302 final SourceIdentifier moduleIdentifier) {
303 final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
304 stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
305 stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);