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