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