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