f07ac611977003ed9580b4854b67a033dba0b154
[yangtools.git] / parser / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / module / ModuleStatementSupport.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.module;
9
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;
13
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;
19 import java.util.Map;
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.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.ImportResolutionMode;
47 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
48 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
49 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
50 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.CommonStmtCtx;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
57 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
58 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
59 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
60 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
61 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
62 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
63 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
64 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
65 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToSourceIdentifier;
66 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
67 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
68 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
69 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
70 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
71 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
72
73 @Beta
74 public final class ModuleStatementSupport
75         extends AbstractStatementSupport<Unqualified, ModuleStatement, ModuleEffectiveStatement> {
76     private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
77         .addAny(YangStmtMapping.ANYXML)
78         .addAny(YangStmtMapping.AUGMENT)
79         .addAny(YangStmtMapping.CHOICE)
80         .addOptional(YangStmtMapping.CONTACT)
81         .addAny(YangStmtMapping.CONTAINER)
82         .addOptional(YangStmtMapping.DESCRIPTION)
83         .addAny(YangStmtMapping.DEVIATION)
84         .addAny(YangStmtMapping.EXTENSION)
85         .addAny(YangStmtMapping.FEATURE)
86         .addAny(YangStmtMapping.GROUPING)
87         .addAny(YangStmtMapping.IDENTITY)
88         .addAny(YangStmtMapping.IMPORT)
89         .addAny(YangStmtMapping.INCLUDE)
90         .addAny(YangStmtMapping.LEAF)
91         .addAny(YangStmtMapping.LEAF_LIST)
92         .addAny(YangStmtMapping.LIST)
93         .addMandatory(YangStmtMapping.NAMESPACE)
94         .addAny(YangStmtMapping.NOTIFICATION)
95         .addOptional(YangStmtMapping.ORGANIZATION)
96         .addMandatory(YangStmtMapping.PREFIX)
97         .addOptional(YangStmtMapping.REFERENCE)
98         .addAny(YangStmtMapping.REVISION)
99         .addAny(YangStmtMapping.RPC)
100         .addAny(YangStmtMapping.TYPEDEF)
101         .addAny(YangStmtMapping.USES)
102         .addOptional(YangStmtMapping.YANG_VERSION)
103         .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
104         .build();
105     private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.MODULE)
106         .addAny(YangStmtMapping.ANYDATA)
107         .addAny(YangStmtMapping.ANYXML)
108         .addAny(YangStmtMapping.AUGMENT)
109         .addAny(YangStmtMapping.CHOICE)
110         .addOptional(YangStmtMapping.CONTACT)
111         .addAny(YangStmtMapping.CONTAINER)
112         .addOptional(YangStmtMapping.DESCRIPTION)
113         .addAny(YangStmtMapping.DEVIATION)
114         .addAny(YangStmtMapping.EXTENSION)
115         .addAny(YangStmtMapping.FEATURE)
116         .addAny(YangStmtMapping.GROUPING)
117         .addAny(YangStmtMapping.IDENTITY)
118         .addAny(YangStmtMapping.IMPORT)
119         .addAny(YangStmtMapping.INCLUDE)
120         .addAny(YangStmtMapping.LEAF)
121         .addAny(YangStmtMapping.LEAF_LIST)
122         .addAny(YangStmtMapping.LIST)
123         .addMandatory(YangStmtMapping.NAMESPACE)
124         .addAny(YangStmtMapping.NOTIFICATION)
125         .addOptional(YangStmtMapping.ORGANIZATION)
126         .addMandatory(YangStmtMapping.PREFIX)
127         .addOptional(YangStmtMapping.REFERENCE)
128         .addAny(YangStmtMapping.REVISION)
129         .addAny(YangStmtMapping.RPC)
130         .addAny(YangStmtMapping.TYPEDEF)
131         .addAny(YangStmtMapping.USES)
132         .addMandatory(YangStmtMapping.YANG_VERSION)
133         .addOptional(OpenConfigStatements.OPENCONFIG_VERSION)
134         .build();
135
136     private final boolean semanticVersioning;
137
138     private ModuleStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
139         super(YangStmtMapping.MODULE, StatementPolicy.reject(), config, validator);
140         semanticVersioning = config.importResolutionMode() == ImportResolutionMode.OPENCONFIG_SEMVER;
141     }
142
143     public static @NonNull ModuleStatementSupport rfc6020Instance(final YangParserConfiguration config) {
144         return new ModuleStatementSupport(config, RFC6020_VALIDATOR);
145     }
146
147     public static @NonNull ModuleStatementSupport rfc7950Instance(final YangParserConfiguration config) {
148         return new ModuleStatementSupport(config, RFC7950_VALIDATOR);
149     }
150
151     @Override
152     public Unqualified parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
153         try {
154             return UnresolvedQName.unqualified(value);
155         } catch (IllegalArgumentException e) {
156             throw new SourceException(e.getMessage(), ctx, e);
157         }
158     }
159
160     @Override
161     public void onPreLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
162         final String moduleName = stmt.getRawArgument();
163
164         final XMLNamespace moduleNs = SourceException.throwIfNull(
165             firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
166             "Namespace of the module [%s] is missing", moduleName);
167         stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
168
169         final String modulePrefix = SourceException.throwIfNull(
170             firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
171             "Prefix of the module [%s] is missing", moduleName);
172         stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
173
174         stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
175
176         final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
177         final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
178
179         stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
180         stmt.setRootIdentifier(RevisionSourceIdentifier.create(stmt.getArgument().getLocalName(), revisionDate));
181     }
182
183     @Override
184     public void onLinkageDeclared(final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt) {
185         final XMLNamespace moduleNs = SourceException.throwIfNull(
186             firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class), stmt,
187             "Namespace of the module [%s] is missing", stmt.argument());
188
189         final Optional<Revision> revisionDate = StmtContextUtils.getLatestRevision(stmt.declaredSubstatements());
190         final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
191         final StmtContext<?, ModuleStatement, ModuleEffectiveStatement> possibleDuplicateModule =
192                 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
193         if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
194             throw new SourceException(stmt, "Module namespace collision: %s. At %s", qNameModule.getNamespace(),
195                 possibleDuplicateModule.sourceReference());
196         }
197
198         final String moduleName = stmt.getRawArgument();
199         final SourceIdentifier moduleIdentifier = RevisionSourceIdentifier.create(moduleName, revisionDate);
200
201         stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
202         stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
203         stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
204
205         final String modulePrefix = SourceException.throwIfNull(
206             firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), stmt,
207             "Prefix of the module [%s] is missing", stmt.argument());
208
209         stmt.addToNs(QNameModuleNamespace.class, Empty.value(), qNameModule);
210         stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
211         stmt.addToNs(ModuleNameToModuleQName.class, moduleName, qNameModule);
212         stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
213         stmt.addToNs(ModuleCtxToSourceIdentifier.class, stmt, moduleIdentifier);
214         stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, moduleName);
215         stmt.addToNs(ImportPrefixToModuleCtx.class, modulePrefix, stmt);
216
217         if (semanticVersioning) {
218             addToSemVerModuleNamespace(stmt, moduleIdentifier);
219         }
220     }
221
222     @Override
223     protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
224             final Current<Unqualified, ModuleStatement> stmt,
225             final List<? extends StmtContext<?, ?, ?>> substatements) {
226         final ImmutableList<? extends EffectiveStatement<?, ?>> local =
227                 super.buildEffectiveSubstatements(stmt, substatements);
228         final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
229         if (submodules.isEmpty()) {
230             return local;
231         }
232
233         // Concatenate statements so they appear as if they were part of target module
234         final List<EffectiveStatement<?, ?>> others = new ArrayList<>();
235         for (StmtContext<?, ?, ?> submoduleCtx : submodules) {
236             for (EffectiveStatement<?, ?> effective : submoduleCtx.buildEffective().effectiveSubstatements()) {
237                 if (effective instanceof SchemaNode || effective instanceof DataNodeContainer) {
238                     others.add(effective);
239                 }
240             }
241         }
242
243         return ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(local.size() + others.size())
244                 .addAll(local)
245                 .addAll(others)
246                 .build();
247     }
248
249     @Override
250     protected ModuleStatement createDeclared(final BoundStmtCtx<Unqualified> ctx,
251             final ImmutableList<DeclaredStatement<?>> substatements) {
252         if (substatements.isEmpty()) {
253             throw noNamespace(ctx);
254         }
255         return DeclaredStatements.createModule(ctx.getRawArgument(), ctx.getArgument(), substatements);
256     }
257
258     @Override
259     protected ModuleStatement attachDeclarationReference(final ModuleStatement stmt,
260             final DeclarationReference reference) {
261         return DeclaredStatementDecorators.decorateModule(stmt, reference);
262     }
263
264     @Override
265     protected ModuleEffectiveStatement createEffective(final Current<Unqualified, ModuleStatement> stmt,
266             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
267         if (substatements.isEmpty()) {
268             throw noNamespace(stmt);
269         }
270
271         final List<Submodule> submodules = new ArrayList<>();
272         for (StmtContext<?, ?, ?> submoduleCtx : submoduleContexts(stmt)) {
273             final EffectiveStatement<?, ?> submodule = submoduleCtx.buildEffective();
274             verify(submodule instanceof Submodule, "Submodule statement %s is not a Submodule", submodule);
275             submodules.add((Submodule) submodule);
276         }
277
278         final QNameModule qnameModule = verifyNotNull(stmt.namespaceItem(QNameModuleNamespace.class, Empty.value()));
279         try {
280             return new ModuleEffectiveStatementImpl(stmt, substatements, submodules, qnameModule);
281         } catch (SubstatementIndexingException e) {
282             throw new SourceException(e.getMessage(), stmt, e);
283         }
284     }
285
286     private static Collection<StmtContext<?, ?, ?>> submoduleContexts(final Current<?, ?> stmt) {
287         final Map<String, StmtContext<?, ?, ?>> submodules = stmt.localNamespacePortion(
288             IncludedSubmoduleNameToModuleCtx.class);
289         return submodules == null ? List.of() : submodules.values();
290     }
291
292     private static SourceException noNamespace(final @NonNull CommonStmtCtx stmt) {
293         return new SourceException("No namespace declared in module", stmt);
294     }
295
296     private static void addToSemVerModuleNamespace(
297             final Mutable<Unqualified, ModuleStatement, ModuleEffectiveStatement> stmt,
298             final SourceIdentifier moduleIdentifier) {
299         final SemVerSourceIdentifier id = SemVerSourceIdentifier.create(stmt.getRawArgument(),
300             stmt.getFromNamespace(SemanticVersionNamespace.class, stmt));
301         stmt.addToNs(SemanticVersionModuleNamespace.class, id, stmt);
302     }
303 }