d4122b61710ec9bc66224e48b581ea03c01255aa
[smo/teiv.git] /
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2024 Ericsson
4  *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21 package org.oran.smo.yangtools.parser.model.statements;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.oran.smo.yangtools.parser.ParserExecutionContext;
27 import org.oran.smo.yangtools.parser.findings.Finding;
28 import org.oran.smo.yangtools.parser.findings.ParserFindingType;
29 import org.oran.smo.yangtools.parser.model.ModulePrefixResolver;
30 import org.oran.smo.yangtools.parser.model.YangModel;
31 import org.oran.smo.yangtools.parser.model.schema.Schema;
32 import org.oran.smo.yangtools.parser.model.statements.yang.YImport;
33 import org.oran.smo.yangtools.parser.model.statements.yang.YInclude;
34 import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
35 import org.oran.smo.yangtools.parser.model.statements.yang.YNamespace;
36 import org.oran.smo.yangtools.parser.model.statements.yang.YPrefix;
37 import org.oran.smo.yangtools.parser.model.statements.yang.YRevision;
38 import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
39 import org.oran.smo.yangtools.parser.model.yangdom.YangDomDocumentRoot;
40 import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
41
42 /**
43  * Root element for a YANG statement tree. Every YAM will result in a tree of type-safe statements.
44  * Usages of groupings and typedefs, augmentations and deviations, and merge-in of submodule content,
45  * will all be performed on the tree (depending on settings in the context).
46  * <p/>
47  * For each YAM, there will be both a Yang DOM element tree (see {@link YangDomDocumentRoot}) and a
48  * YANG statement tree. However, these are not the exact same, and it is important to understand the
49  * difference:
50  * <p/>
51  * <ul>
52  * <li>The Yang DOM element tree is an exact 1:1 representation of the original YAM. It is the result
53  * of the parse of the YAM. During runtime of the parser it does not change, with some marked
54  * exceptions (see {@link YangDomDocumentRoot}).</li>
55  * <li>The YANG statement tree is the end result of applying various Yang statements (such as augment)
56  * to the YAM. This means that the YANG statement tree for a given YAM may end up pointing to DOM
57  * elements located in a different YAM (eg. the YAM that contains the 'augment' statement).</li>
58  * </ul>
59  * <p/>
60  * For compliant YAMs, an instance of this class will only ever have a single child statement (of type
61  * YModule or YSubmodule).
62  *
63  * @author Mark Hollmann
64  */
65 public class YangModelRoot extends AbstractStatement {
66
67     /**
68      * Pointer to the root of the corresponding Yang DOM element tree.
69      */
70     private final YangDomDocumentRoot domDocumentRoot;
71
72     private final Schema owningSchema;
73
74     private YModule module = null;
75     private YSubmodule submodule = null;
76
77     /**
78      * This is the model root of the owner of this YAM. This is either the module itself (i.e. "this")
79      * or the module owning this submodule.
80      */
81     private YangModelRoot owningYangModelRoot = this;
82
83     /**
84      * The submodules owned by this module here, if any.
85      */
86     private List<YangModelRoot> ownedSubmodules = new ArrayList<>();
87
88     public YangModelRoot(final YangDomDocumentRoot domDocumentRoot, final Schema owningSchema) {
89         super(domDocumentRoot);
90         this.domDocumentRoot = domDocumentRoot;
91         this.owningSchema = owningSchema;
92     }
93
94     @Override
95     public StatementArgumentType getArgumentType() {
96         return StatementArgumentType.NO_ARG;
97     }
98
99     public YangDomDocumentRoot getDomDocumentRoot() {
100         return domDocumentRoot;
101     }
102
103     public Schema getOwningSchema() {
104         return owningSchema;
105     }
106
107     public YangModel getYangModel() {
108         return domDocumentRoot.getYangModel();
109     }
110
111     /**
112      * Will tweak the pointer to point at the module that owns this module here.
113      */
114     public void setOwningYangModelRoot(final YangModelRoot owningYangModelRoot) {
115         this.owningYangModelRoot = owningYangModelRoot;
116         if (owningYangModelRoot != null) {
117             this.owningYangModelRoot.ownedSubmodules.add(this);
118         }
119     }
120
121     /**
122      * Returns the module owning this submodule. Returns "this" if this YAM is a module.
123      */
124     public YangModelRoot getOwningYangModelRoot() {
125         return owningYangModelRoot;
126     }
127
128     /**
129      * Returns the submodules owned by this module. Will be empty if this YAM here is a
130      * submodule, or if this module has no submodules.
131      */
132     public List<YangModelRoot> getOwnedSubmodules() {
133         return ownedSubmodules;
134     }
135
136     /**
137      * The namespace of the module, or the namespace of the owning module if this here is a submodule.
138      * May return null if a namespace has not been defined on the module, or the submodule is orphaned.
139      */
140     public String getNamespace() {
141
142         if (isModule()) {
143             final YNamespace yNamespace = module.getNamespace();
144             return yNamespace != null ? yNamespace.getValue() : null;
145         }
146
147         return owningYangModelRoot != null ? owningYangModelRoot.getNamespace() : null;
148     }
149
150     @Override
151     public ModulePrefixResolver getPrefixResolver() {
152         return getYangModel().getPrefixResolver();
153     }
154
155     @Override
156     protected void validate(ParserExecutionContext context) {
157         // nothing to validate
158     }
159
160     public YModule getModule() {
161         return module;
162     }
163
164     public YSubmodule getSubmodule() {
165         return submodule;
166     }
167
168     @SuppressWarnings("unchecked")
169     public <T extends AbstractStatement> T getModuleOrSubmodule() {
170         return module != null ? (T) module : (T) submodule;
171     }
172
173     /**
174      * Processes the DOM and starts building the statement tree in accordance with the DOM.
175      */
176     public void processYangDom(final ParserExecutionContext context, final YangDomDocumentRoot domDocRoot) {
177
178         final List<YangDomElement> childrenOfDocRoot = domDocRoot.getChildren();
179         if (childrenOfDocRoot.size() != 1) {
180             context.addFinding(new Finding(getYangModel(), ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
181                     "Expected single statement ('module' or 'submodule')."));
182             return;
183         }
184
185         final YangDomElement moduleElement = childrenOfDocRoot.get(0).getName().equals("module") ?
186                 childrenOfDocRoot.get(0) :
187                 null;
188         final YangDomElement submoduleElement = childrenOfDocRoot.get(0).getName().equals("submodule") ?
189                 childrenOfDocRoot.get(0) :
190                 null;
191
192         if (moduleElement != null) {
193             module = new YModule(this, moduleElement);
194             module.process(context);
195         } else if (submoduleElement != null) {
196             submodule = new YSubmodule(this, submoduleElement);
197             submodule.process(context);
198         } else {
199             context.addFinding(new Finding(getYangModel(), ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
200                     "Expected either 'module' or 'submodule' as root-statement in the document."));
201         }
202     }
203
204     public boolean isModule() {
205         return module != null;
206     }
207
208     public boolean isSubmodule() {
209         return submodule != null;
210     }
211
212     /**
213      * The module / submodule name will always be non-null.
214      */
215     public String getModuleOrSubModuleName() {
216         return isModule() ? module.getModuleName() : submodule.getSubmoduleName();
217     }
218
219     public List<YRevision> getRevisions() {
220         return isModule() ? module.getRevisions() : submodule.getRevisions();
221     }
222
223     public List<YImport> getImports() {
224         return isModule() ? module.getImports() : submodule.getImports();
225     }
226
227     public List<YInclude> getIncludes() {
228         return isModule() ? module.getIncludes() : submodule.getIncludes();
229     }
230
231     /**
232      * Returns the prefix statement of the module, or the prefix statement underneath the 'belongs-to' if
233      * it is a submodule. May return null if the prefix statement does not exist (which would be a very
234      * basic error).
235      */
236     public YPrefix getPrefix() {
237         return isModule() ?
238                 module.getPrefix() :
239                 submodule.getBelongsTo() != null ? submodule.getBelongsTo().getPrefix() : null;
240     }
241
242     public String getYangVersion() {
243         if (isModule()) {
244             return module.getYangVersion() == null ? "1" : module.getYangVersion().getValue();
245         }
246
247         return submodule.getYangVersion() == null ? "1" : submodule.getYangVersion().getValue();
248     }
249 }