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