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