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 org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
14 import com.google.common.annotations.Beta;
15 import com.google.common.collect.ImmutableList;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.Empty;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.common.Revision;
24 import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified;
25 import org.opendaylight.yangtools.yang.common.XMLNamespace;
26 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
27 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.Submodule;
29 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
30 import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
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.SourceIdentifier;
38 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatementDecorators;
39 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
40 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
41 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
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.AbstractStatementSupport;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
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.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 AbstractStatementSupport<Unqualified, ModuleStatement, ModuleEffectiveStatement> {
68 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
69 .addAny(YangStmtMapping.ANYXML)
70 .addAny(YangStmtMapping.AUGMENT)
71 .addAny(YangStmtMapping.CHOICE)
72 .addOptional(YangStmtMapping.CONTACT)
73 .addAny(YangStmtMapping.CONTAINER)
74 .addOptional(YangStmtMapping.DESCRIPTION)
75 .addAny(YangStmtMapping.DEVIATION)
76 .addAny(YangStmtMapping.EXTENSION)
77 .addAny(YangStmtMapping.FEATURE)
78 .addAny(YangStmtMapping.GROUPING)
79 .addAny(YangStmtMapping.IDENTITY)
80 .addAny(YangStmtMapping.IMPORT)
81 .addAny(YangStmtMapping.INCLUDE)
82 .addAny(YangStmtMapping.LEAF)
83 .addAny(YangStmtMapping.LEAF_LIST)
84 .addAny(YangStmtMapping.LIST)
85 .addMandatory(YangStmtMapping.NAMESPACE)
86 .addAny(YangStmtMapping.NOTIFICATION)
87 .addOptional(YangStmtMapping.ORGANIZATION)
88 .addMandatory(YangStmtMapping.PREFIX)
89 .addOptional(YangStmtMapping.REFERENCE)
90 .addAny(YangStmtMapping.REVISION)
91 .addAny(YangStmtMapping.RPC)
92 .addAny(YangStmtMapping.TYPEDEF)
93 .addAny(YangStmtMapping.USES)
94 .addOptional(YangStmtMapping.YANG_VERSION)
96 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
97 .addAny(YangStmtMapping.ANYDATA)
98 .addAny(YangStmtMapping.ANYXML)
99 .addAny(YangStmtMapping.AUGMENT)
100 .addAny(YangStmtMapping.CHOICE)
101 .addOptional(YangStmtMapping.CONTACT)
102 .addAny(YangStmtMapping.CONTAINER)
103 .addOptional(YangStmtMapping.DESCRIPTION)
104 .addAny(YangStmtMapping.DEVIATION)
105 .addAny(YangStmtMapping.EXTENSION)
106 .addAny(YangStmtMapping.FEATURE)
107 .addAny(YangStmtMapping.GROUPING)
108 .addAny(YangStmtMapping.IDENTITY)
109 .addAny(YangStmtMapping.IMPORT)
110 .addAny(YangStmtMapping.INCLUDE)
111 .addAny(YangStmtMapping.LEAF)
112 .addAny(YangStmtMapping.LEAF_LIST)
113 .addAny(YangStmtMapping.LIST)
114 .addMandatory(YangStmtMapping.NAMESPACE)
115 .addAny(YangStmtMapping.NOTIFICATION)
116 .addOptional(YangStmtMapping.ORGANIZATION)
117 .addMandatory(YangStmtMapping.PREFIX)
118 .addOptional(YangStmtMapping.REFERENCE)
119 .addAny(YangStmtMapping.REVISION)
120 .addAny(YangStmtMapping.RPC)
121 .addAny(YangStmtMapping.TYPEDEF)
122 .addAny(YangStmtMapping.USES)
123 .addMandatory(YangStmtMapping.YANG_VERSION)
126 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
127 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
130 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
131 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
134 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
135 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
139 public Unqualified parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
141 return Unqualified.of(value);
142 } catch (IllegalArgumentException e) {
143 throw new SourceException(e.getMessage(), ctx, e);
148 public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
149 final Unqualified moduleName = stmt.getArgument();
151 final XMLNamespace moduleNs = SourceException.throwIfNull(
152 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
153 "Namespace of the module [%s] is missing", moduleName);
154 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
156 final String modulePrefix = SourceException.throwIfNull(
157 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
158 "Prefix of the module [%s] is missing", moduleName);
159 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
161 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
163 final Revision revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements()).orElse(null);
164 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate).intern();
166 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
167 stmt.setRootIdentifier(new SourceIdentifier(stmt.getArgument(), revisionDate));
171 public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
172 final XMLNamespace moduleNs = SourceException.throwIfNull(
173 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
174 "Namespace of the module [%s] is missing", stmt.argument());
176 final Revision revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements()).orElse(null);
177 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate).intern();
178 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
179 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
180 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
181 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
182 possibleDuplicateModule.sourceReference());
185 final Unqualified moduleName = stmt.getArgument();
186 final SourceIdentifier moduleIdentifier = new SourceIdentifier(moduleName, revisionDate);
188 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
189 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleName, stmt);
190 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
192 final String modulePrefix = SourceException.throwIfNull(
193 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
194 "Prefix of the module [%s] is missing", stmt.argument());
196 stmt.addToNs(QNameModuleNamespace.class, Empty.value(), qNameModule);
197 stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
198 stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
199 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
200 stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
201 stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
202 stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
206 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
207 final Current<Unqualified, ModuleStatement> stmt,
208 final List<? extends StmtContext<?, ?, ?>> substatements) {
209 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
210 super.buildEffectiveSubstatements(stmt, substatements);
211 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
212 if (submodules.isEmpty()) {
216 // Concatenate statements so they appear as if they were part of target module
217 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
218 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
219 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
220 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
221 others.add(effective);
226 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
233 protected ModuleStatement createDeclared(final BoundStmtCtx<Unqualified> ctx,
234 final ImmutableList<DeclaredStatement<?>> substatements) {
235 if (substatements.isEmpty()) {
236 throw noNamespace(ctx);
238 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
242 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
243 final DeclarationReference reference) {
244 return DeclaredStatementDecorators.decorateModule(stmt, reference);
248 protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
249 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
250 if (substatements.isEmpty()) {
251 throw noNamespace(stmt);
254 final List<Submodule> submodules = new ArrayList<>();
255 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
256 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
257 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
258 submodules.add((Submodule) submodule);
261 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class, Empty.value()));
263 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
264 } catch (SubstatementIndexingException e) {
265 throw new SourceException(e.getMessage(), stmt, e);
269 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
270 final Map<Unqualified, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
271 IncludedSubmoduleNameToModuleCtx.class);
272 return submodules == null ? List.of() : submodules.values();
275 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
276 return new SourceException("No namespace declared in module", stmt);