430247577c7e43a544f340989f8c35c51da9237a
[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.data.instance;
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.function.Predicate;
30 import java.util.stream.Collectors;
31
32 import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
33 import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
34 import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
35
36 /**
37  * This class represents a structural element, which can be either a true (singleton)
38  * container, or an instance of a list.
39  *
40  * @author Mark Hollmann
41  */
42 public abstract class AbstractStructureInstance extends AbstractDataInstance {
43
44     /**
45      * The child structure instances, if any (i.e. containers / lists under this container / list).
46      */
47     private final List<AbstractStructureInstance> structureChildren = new ArrayList<>();
48
49     /**
50      * The content values, if any (non-presence containers are usually empty), of the structure (i.e. leaf or leaf-list
51      * data).
52      */
53     private final List<AbstractContentInstance> contentChildren = new ArrayList<>();
54
55     private Set<NamespaceModuleIdentifier> emptyChildLeafListIdentifiers;
56
57     /**
58      * Constructor for a structure instance that was specified in data.
59      */
60     public AbstractStructureInstance(final AbstractStatement schemaNode, final YangDataDomNode dataDomNode,
61             final AbstractStructureInstance parent) {
62         super(schemaNode, dataDomNode, parent);
63     }
64
65     /**
66      * Constructor for a structure instance that was created by default (i.e. not specified in data).
67      */
68     public AbstractStructureInstance(final AbstractStatement schemaNode, final AbstractStructureInstance parent) {
69         super(schemaNode, parent);
70     }
71
72     public void addStructureChild(final AbstractStructureInstance structureChild) {
73         structureChildren.add(structureChild);
74     }
75
76     public List<AbstractStructureInstance> getStructureChildren() {
77         return structureChildren;
78     }
79
80     public void addContentChild(final AbstractContentInstance contentChild) {
81         contentChildren.add(contentChild);
82     }
83
84     public List<AbstractContentInstance> getContentChildren() {
85         return contentChildren;
86     }
87
88     public void setEmptyChildLeafListIdentifiers(final Set<NamespaceModuleIdentifier> val) {
89         this.emptyChildLeafListIdentifiers = val;
90     }
91
92     public void addEmptyChildLeafListIdentifiers(final Set<NamespaceModuleIdentifier> toAdd) {
93         if (toAdd.isEmpty()) {
94             return;
95         }
96         if (emptyChildLeafListIdentifiers == null) {
97             emptyChildLeafListIdentifiers = new HashSet<>();
98         }
99         emptyChildLeafListIdentifiers.addAll(toAdd);
100     }
101
102     public Set<NamespaceModuleIdentifier> getEmptyChildLeafListIdentifiers() {
103         return emptyChildLeafListIdentifiers == null ? Collections.emptySet() : emptyChildLeafListIdentifiers;
104     }
105
106     /**
107      * Returns the container instance of the given namespace and name. May return null if not found.
108      */
109     public ContainerInstance getContainerInstance(final String namespace, final String name) {
110         return (ContainerInstance) structureChildren.stream().filter(new InstanceTester(namespace, name,
111                 ContainerInstance.class)).findFirst().orElse(null);
112     }
113
114     public boolean hasContainerInstance(final String namespace, final String name) {
115         return structureChildren.stream().filter(new InstanceTester(namespace, name, ContainerInstance.class)).findFirst()
116                 .isPresent();
117     }
118
119     /**
120      * Returns the leaf instance of the given namespace and name. May return null if not found.
121      */
122     public LeafInstance getLeafInstance(final String namespace, final String name) {
123         return (LeafInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, LeafInstance.class))
124                 .findFirst().orElse(null);
125     }
126
127     public boolean hasLeafInstance(final String namespace, final String name) {
128         return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafInstance.class)).findFirst()
129                 .isPresent();
130     }
131
132     /**
133      * Returns all occurrences of list instances of the given namespace and name.
134      */
135     public List<ListInstance> getListInstances(final String namespace, final String name) {
136         return (List<ListInstance>) structureChildren.stream().filter(new InstanceTester(namespace, name,
137                 ListInstance.class)).map(child -> (ListInstance) child).collect(Collectors.toList());
138     }
139
140     public ListInstance getListInstance(final String namespace, final String name, final Map<String, String> keyValues) {
141         return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).map(
142                 child -> (ListInstance) child).filter(listChild -> keyValues.equals(listChild.getKeyValues())).findFirst()
143                 .orElse(null);
144     }
145
146     public boolean hasListInstance(final String namespace, final String name) {
147         return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).findFirst()
148                 .isPresent();
149     }
150
151     public boolean hasListInstance(final String namespace, final String name, final Map<String, String> keyValues) {
152         return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).filter(
153                 child -> keyValues.equals(((ListInstance) child).getKeyValues())).findFirst().isPresent();
154     }
155
156     /**
157      * Returns all occurrences of leaf-list instances of the given namespace and name.
158      */
159     public List<LeafListInstance> getLeafListInstances(final String namespace, final String name) {
160         return (List<LeafListInstance>) contentChildren.stream().filter(new InstanceTester(namespace, name,
161                 LeafListInstance.class)).map(child -> (LeafListInstance) child).collect(Collectors.toList());
162     }
163
164     /**
165      * Returns the values of leaf-list. Note that the order may be undefined where a merge of multiple inputs happened.
166      */
167     public List<Object> getLeafListValues(final String namespace, final String name) {
168         return (List<Object>) contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class))
169                 .map(child -> ((LeafListInstance) child).getValue()).collect(Collectors.toList());
170     }
171
172     public boolean hasLeafListInstance(final String namespace, final String name) {
173         return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class)).findFirst()
174                 .isPresent();
175     }
176
177     public boolean hasLeafListInstance(final String namespace, final String name, final Object value) {
178         return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class)).filter(
179                 child -> value.equals(((LeafListInstance) child).getValue())).findFirst().isPresent();
180     }
181
182     /**
183      * Returns the anydata instance of the given namespace and name. May return null if not found.
184      */
185     public AnyDataInstance getAnyDataInstance(final String namespace, final String name) {
186         return (AnyDataInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, AnyDataInstance.class))
187                 .findFirst().orElse(null);
188     }
189
190     public boolean hasAnyDataInstance(final String namespace, final String name) {
191         return contentChildren.stream().filter(new InstanceTester(namespace, name, AnyDataInstance.class)).findFirst()
192                 .isPresent();
193     }
194
195     /**
196      * Returns the anyxml instance of the given namespace and name. May return null if not found.
197      */
198     public AnyXmlInstance getAnyXmlInstance(final String namespace, final String name) {
199         return (AnyXmlInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, AnyXmlInstance.class))
200                 .findFirst().orElse(null);
201     }
202
203     public boolean hasAnyXmlInstance(final String namespace, final String name) {
204         return contentChildren.stream().filter(new InstanceTester(namespace, name, AnyXmlInstance.class)).findFirst()
205                 .isPresent();
206     }
207
208     private class InstanceTester implements Predicate<AbstractDataInstance> {
209
210         private final String namespace;
211         private final String name;
212         private final Class<? extends AbstractDataInstance> soughtClazz;
213
214         public <T extends AbstractDataInstance> InstanceTester(final String namespace, final String name,
215                 final Class<T> soughtClazz) {
216             this.namespace = namespace;
217             this.name = name;
218             this.soughtClazz = soughtClazz;
219         }
220
221         @Override
222         public boolean test(final AbstractDataInstance dataInstance) {
223             return name.equals(dataInstance.getName()) && namespace.equals(dataInstance.getNamespace()) && (dataInstance
224                     .getClass().equals(soughtClazz));
225         }
226     }
227
228     /**
229      * Returns a human-readable string with the full path to the Container node.
230      */
231     public String getPath() {
232
233         final List<AbstractStructureInstance> containersFromRoot = new ArrayList<>(10);
234         AbstractStructureInstance runContainer = this;
235
236         while (runContainer != null) {
237             containersFromRoot.add(0, runContainer);
238             runContainer = runContainer.getParent();
239         }
240
241         final StringBuilder sb = new StringBuilder();
242         for (final AbstractStructureInstance container : containersFromRoot) {
243             sb.append('/').append(container.getName());
244         }
245
246         return sb.toString();
247     }
248
249 }