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.stream.Stream;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.yangtools.yang.common.Empty;
23 import org.opendaylight.yangtools.yang.common.QNameModule;
24 import org.opendaylight.yangtools.yang.common.Revision;
25 import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified;
26 import org.opendaylight.yangtools.yang.common.XMLNamespace;
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
28 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.Submodule;
30 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
31 import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
32 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
33 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
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.ri.stmt.DeclaredStatementDecorators;
40 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
41 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
42 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
43 import org.opendaylight.yangtools.yang.parser.spi.ParserNamespaces;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractUnqualifiedStatementSupport;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
52 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
55 public final class ModuleStatementSupport
56 extends AbstractUnqualifiedStatementSupport<ModuleStatement, ModuleEffectiveStatement> {
57 private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
58 .addAny(YangStmtMapping.ANYXML)
59 .addAny(YangStmtMapping.AUGMENT)
60 .addAny(YangStmtMapping.CHOICE)
61 .addOptional(YangStmtMapping.CONTACT)
62 .addAny(YangStmtMapping.CONTAINER)
63 .addOptional(YangStmtMapping.DESCRIPTION)
64 .addAny(YangStmtMapping.DEVIATION)
65 .addAny(YangStmtMapping.EXTENSION)
66 .addAny(YangStmtMapping.FEATURE)
67 .addAny(YangStmtMapping.GROUPING)
68 .addAny(YangStmtMapping.IDENTITY)
69 .addAny(YangStmtMapping.IMPORT)
70 .addAny(YangStmtMapping.INCLUDE)
71 .addAny(YangStmtMapping.LEAF)
72 .addAny(YangStmtMapping.LEAF_LIST)
73 .addAny(YangStmtMapping.LIST)
74 .addMandatory(YangStmtMapping.NAMESPACE)
75 .addAny(YangStmtMapping.NOTIFICATION)
76 .addOptional(YangStmtMapping.ORGANIZATION)
77 .addMandatory(YangStmtMapping.PREFIX)
78 .addOptional(YangStmtMapping.REFERENCE)
79 .addAny(YangStmtMapping.REVISION)
80 .addAny(YangStmtMapping.RPC)
81 .addAny(YangStmtMapping.TYPEDEF)
82 .addAny(YangStmtMapping.USES)
83 .addOptional(YangStmtMapping.YANG_VERSION)
85 private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
86 .addAny(YangStmtMapping.ANYDATA)
87 .addAny(YangStmtMapping.ANYXML)
88 .addAny(YangStmtMapping.AUGMENT)
89 .addAny(YangStmtMapping.CHOICE)
90 .addOptional(YangStmtMapping.CONTACT)
91 .addAny(YangStmtMapping.CONTAINER)
92 .addOptional(YangStmtMapping.DESCRIPTION)
93 .addAny(YangStmtMapping.DEVIATION)
94 .addAny(YangStmtMapping.EXTENSION)
95 .addAny(YangStmtMapping.FEATURE)
96 .addAny(YangStmtMapping.GROUPING)
97 .addAny(YangStmtMapping.IDENTITY)
98 .addAny(YangStmtMapping.IMPORT)
99 .addAny(YangStmtMapping.INCLUDE)
100 .addAny(YangStmtMapping.LEAF)
101 .addAny(YangStmtMapping.LEAF_LIST)
102 .addAny(YangStmtMapping.LIST)
103 .addMandatory(YangStmtMapping.NAMESPACE)
104 .addAny(YangStmtMapping.NOTIFICATION)
105 .addOptional(YangStmtMapping.ORGANIZATION)
106 .addMandatory(YangStmtMapping.PREFIX)
107 .addOptional(YangStmtMapping.REFERENCE)
108 .addAny(YangStmtMapping.REVISION)
109 .addAny(YangStmtMapping.RPC)
110 .addAny(YangStmtMapping.TYPEDEF)
111 .addAny(YangStmtMapping.USES)
112 .addMandatory(YangStmtMapping.YANG_VERSION)
115 private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
116 super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
119 public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
120 return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
123 public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
124 return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
128 public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
129 final Unqualified moduleName = stmt.getArgument();
131 final XMLNamespace moduleNs = SourceException.throwIfNull(
132 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
133 "Namespace of the module [%s] is missing", moduleName);
134 stmt.addToNs(ParserNamespaces.MODULE_NAME_TO_NAMESPACE, moduleName, moduleNs);
136 final String modulePrefix = SourceException.throwIfNull(
137 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
138 "Prefix of the module [%s] is missing", moduleName);
139 stmt.addToNs(ParserNamespaces.IMP_PREFIX_TO_NAMESPACE, modulePrefix, moduleNs);
141 stmt.addToNs(ParserNamespaces.PRELINKAGE_MODULE, moduleName, stmt);
143 final Revision revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements()).orElse(null);
144 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate).intern();
146 stmt.addToNs(ParserNamespaces.MODULECTX_TO_QNAME, stmt, qNameModule);
147 stmt.setRootIdentifier(new SourceIdentifier(stmt.getArgument(), revisionDate));
151 public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
152 final XMLNamespace moduleNs = SourceException.throwIfNull(
153 firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
154 "Namespace of the module [%s] is missing", stmt.argument());
156 final Revision revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements()).orElse(null);
157 final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate).intern();
158 final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
159 stmt.namespaceItem(ParserNamespaces.NAMESPACE_TO_MODULE, qNameModule);
160 if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
161 throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
162 possibleDuplicateModule.sourceReference());
165 final Unqualified moduleName = stmt.getArgument();
166 final SourceIdentifier moduleIdentifier = new SourceIdentifier(moduleName, revisionDate);
168 stmt.addToNs(ParserNamespaces.MODULE, moduleIdentifier, stmt);
169 stmt.addToNs(ParserNamespaces.MODULE_FOR_BELONGSTO, moduleName, stmt);
170 stmt.addToNs(ParserNamespaces.NAMESPACE_TO_MODULE, qNameModule, stmt);
172 final String modulePrefix = SourceException.throwIfNull(
173 firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
174 "Prefix of the module [%s] is missing", stmt.argument());
176 stmt.addToNs(QNameModuleNamespace.INSTANCE, Empty.value(), qNameModule);
177 stmt.addToNs(ParserNamespaces.PREFIX_TO_MODULE, modulePrefix, qNameModule);
178 stmt.addToNs(ParserNamespaces.MODULE_NAME_TO_QNAME, moduleName, qNameModule);
179 stmt.addToNs(ParserNamespaces.MODULECTX_TO_QNAME, stmt, qNameModule);
180 stmt.addToNs(ParserNamespaces.MODULECTX_TO_SOURCE, stmt, moduleIdentifier);
181 stmt.addToNs(ParserNamespaces.MODULE_NAMESPACE_TO_NAME, qNameModule, moduleName);
182 stmt.addToNs(ParserNamespaces.IMPORT_PREFIX_TO_MODULECTX, modulePrefix, stmt);
186 protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
187 final Current<Unqualified, ModuleStatement> stmt,
188 final Stream<? extends StmtContext<?, ?, ?>> substatements) {
189 final ImmutableList<? extends EffectiveStatement<?, ?>> local =
190 super.buildEffectiveSubstatements(stmt, substatements);
191 final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
192 if (submodules.isEmpty()) {
196 // Concatenate statements so they appear as if they were part of target module
197 final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
198 for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
199 for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
200 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
201 others.add(effective);
206 return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
213 protected ModuleStatement createDeclared(final BoundStmtCtx<Unqualified> ctx,
214 final ImmutableList<DeclaredStatement<?>> substatements) {
215 if (substatements.isEmpty()) {
216 throw noNamespace(ctx);
218 return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
222 protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
223 final DeclarationReference reference) {
224 return DeclaredStatementDecorators.decorateModule(stmt, reference);
228 protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
229 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
230 if (substatements.isEmpty()) {
231 throw noNamespace(stmt);
234 final List<Submodule> submodules = new ArrayList<>();
235 for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
236 final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
237 verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
238 submodules.add((Submodule) submodule);
241 final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.INSTANCE, Empty.value()));
243 return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
244 } catch (SubstatementIndexingException e) {
245 throw new SourceException(e.getMessage(), stmt, e);
249 private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
250 final Map<Unqualified, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
251 ParserNamespaces.INCLUDED_SUBMODULE_NAME_TO_MODULECTX);
252 return submodules == null ? List.of() : submodules.values();
255 private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
256 return new SourceException("No namespace declared in module", stmt);