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 java.util.Optional;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.yangtools.openconfig.model.api.OpenConfigStatements;
23 import org.opendaylight.yangtools.yang.common.Empty;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25 import org.opendaylight.yangtools.yang.common.Revision;
26 import org.opendaylight.yangtools.yang.common.UnresolvedQName;
27 import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified;
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.SourceIdentifier;
42 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatementDecorators;
43 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
44 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
45 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
46 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
47 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
48 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
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.StmtContext;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
57 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
58 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
59 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
60 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
63 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
66 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
67 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
70 public final class ModuleStatementSupport
71 extends AbstractStatementSupport<Unqualified, ModuleStatement, ModuleEffectiveStatement> {
72 private static final SubstatementValidator RFC6020_VALIDATOR = 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 SubstatementValidator RFC7950_VALIDATOR = 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 ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
133 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
136 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
137 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
140 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
141 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
145 public Unqualified parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
147 return UnresolvedQName.unqualified(value);
148 } catch (IllegalArgumentException e) {
149 throw new SourceException(e.getMessage(), ctx, e);
154 public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
155 final String moduleName = stmt.getRawArgument();
157 final XMLNamespace moduleNs = SourceException.throwIfNull(
158 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
159 "Namespace of the module [%s] is missing", moduleName);
160 stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
162 final String modulePrefix = SourceException.throwIfNull(
163 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
164 "Prefix of the module [%s] is missing", moduleName);
165 stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
167 stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
169 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
170 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
172 stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
173 stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
177 public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
178 final XMLNamespace moduleNs = SourceException.throwIfNull(
179 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
180 "Namespace of the module [%s] is missing", stmt.argument());
182 final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
183 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
184 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
185 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
186 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
187 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
188 possibleDuplicateModule.sourceReference());
191 final String moduleName = stmt.getRawArgument();
192 final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
194 stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
195 stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
196 stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
198 final String modulePrefix = SourceException.throwIfNull(
199 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
200 "Prefix of the module [%s] is missing", stmt.argument());
202 stmt.addToNs(QNameModuleNamespace.class, Empty.value(), qNameModule);
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);
212 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
213 final Current<Unqualified, ModuleStatement> stmt,
214 final List<? extends StmtContext<?, ?, ?>> substatements) {
215 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
216 super.buildEffectiveSubstatements(stmt, substatements);
217 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
218 if (submodules.isEmpty()) {
222 // Concatenate statements so they appear as if they were part of target module
223 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
224 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
225 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
226 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
227 others.add(effective);
232 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
239 protected ModuleStatement createDeclared(final BoundStmtCtx<Unqualified> ctx,
240 final ImmutableList<DeclaredStatement<?>> substatements) {
241 if (substatements.isEmpty()) {
242 throw noNamespace(ctx);
244 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
248 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
249 final DeclarationReference reference) {
250 return DeclaredStatementDecorators.decorateModule(stmt, reference);
254 protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
255 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
256 if (substatements.isEmpty()) {
257 throw noNamespace(stmt);
260 final List<Submodule> submodules = new ArrayList<>();
261 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
262 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
263 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
264 submodules.add((Submodule) submodule);
267 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class, Empty.value()));
269 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
270 } catch (SubstatementIndexingException e) {
271 throw new SourceException(e.getMessage(), stmt, e);
275 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
276 final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
277 IncludedSubmoduleNameToModuleCtx.class);
278 return submodules == null ? List.of() : submodules.values();
281 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
282 return new SourceException("No namespace declared in module", stmt);