Issue fix for RestconfApiCallNode
[ccsdk/sli/plugins.git] / restconf-client / provider / src / main / java / org / onap / ccsdk / sli / plugins / yangserializers / dfserializer / MdsalSerializerHelper.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - CCSDK
4  * ================================================================================
5  * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer;
22
23 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
24 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace;
25 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType;
26 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode;
27 import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.common.Revision;
30 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
36 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
39
40 import java.util.Deque;
41
42 import static java.lang.String.format;
43 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.DF_ERR;
44 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR;
45 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.PROP_NODE_ERR;
46 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getResolvedNamespace;
47 import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.resolveBaseTypeFrom;
48 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision;
49 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE;
50 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE;
51 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE;
52 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE;
53 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE;
54 import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE;
55 import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findDataChildSchemaByQName;
56 import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findSchemaForChild;
57 import static org.opendaylight.yangtools.yang.data.util.ParserStreamUtils.findSchemaNodeByNameAndNamespace;
58
59 /**
60  * Representation of MDSAL based serializer helper, which adds properties
61  * node to the properties tree based on its types.
62  */
63 public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaContext> {
64
65     /**
66      * Current properties node.
67      */
68     private PropertiesNode propNode;
69
70     /**
71      * Current schema node.
72      */
73     private SchemaNode curSchemaNode;
74
75
76     /**
77      * Creates MDSAL serializer helper with root schema node, schema context
78      * and URI.
79      *
80      * @param n schema node of the URI's last node
81      * @param c schema context
82      * @param u URI of the request
83      */
84     public MdsalSerializerHelper(SchemaNode n, SchemaContext c,
85                                  String u) {
86         super(n, c, u);
87         Namespace ns = new Namespace(n.getQName().getLocalName(),
88                                      n.getQName().getNamespace(),
89                                      getRevision(n.getQName().getRevision()));
90         propNode = new RootNode<>(n.getQName().getLocalName(), ns,
91                                   getSchemaNode(), u);
92         curSchemaNode = getSchemaNode();
93     }
94
95     @Override
96     protected SchemaNode getSchemaNode() {
97         return schemaNode;
98     }
99
100     @Override
101     protected SchemaContext getSchemaCtx() {
102         return schemaCtx;
103     }
104
105     @Override
106     protected SchemaNode getCurSchema() {
107         return curSchemaNode;
108     }
109
110     @Override
111     protected void addNode(String name, String nameSpace, String value,
112                            String valNameSpace, NodeType type)
113             throws SvcLogicException {
114         Namespace ns;
115         if (type == null) {
116             ns = getResolvedNamespace(null, nameSpace,
117                                       getSchemaCtx(), propNode);
118         } else {
119             ns = getResolvedNamespace(nameSpace, null,
120                                       getSchemaCtx(), propNode);
121         }
122         if (isChildPresent(name, ns)) {
123             addNodeToProperty(name, ns, value, valNameSpace, type);
124         } else {
125             throw new SvcLogicException(format(
126                     "Unable to add the node %s", name));
127         }
128     }
129
130     @Override
131     protected void exitNode() throws SvcLogicException {
132         propNode = propNode.parent();
133         if (propNode != null) {
134             NodeType type = propNode.nodeType();
135             if (type == MULTI_INSTANCE_HOLDER_NODE ||
136                     type == MULTI_INSTANCE_LEAF_HOLDER_NODE) {
137                 propNode = propNode.parent();
138             }
139         }
140         if (propNode == null || propNode.appInfo() == null
141                 || !(propNode.appInfo() instanceof SchemaNode)) {
142             throw new SvcLogicException(PROP_NODE_ERR);
143         }
144         curSchemaNode = (SchemaNode) propNode.appInfo();
145     }
146
147     @Override
148     protected PropertiesNode getPropertiesNode() {
149         return propNode;
150     }
151
152     /**
153      * Adds the node to property node based on the type of the schema node,
154      * which is decided based on the name and namespace of the input
155      * information.
156      *
157      * @param name         name of the node
158      * @param ns           namespace of the node
159      * @param value        value of the node if its a leaf/leaf-list
160      * @param valNamespace namespace of the value
161      * @param type         type of the node
162      * @throws SvcLogicException when adding child fails
163      */
164     private void addNodeToProperty(String name, Namespace ns, String value,
165                                    String valNamespace, NodeType type)
166             throws SvcLogicException {
167         Namespace valueNs;
168         if (type != null) {
169             validateNodeType(type);
170         }
171         if (curSchemaNode instanceof LeafSchemaNode) {
172             valueNs = getValueNs(curSchemaNode, valNamespace, type);
173             propNode = propNode.addChild(name, ns,
174                                          SINGLE_INSTANCE_LEAF_NODE,
175                                          value, valueNs, curSchemaNode);
176         } else if (curSchemaNode instanceof LeafListSchemaNode) {
177             valueNs = getValueNs(curSchemaNode, valNamespace, type);
178             propNode = propNode.addChild(null, name, ns,
179                                          MULTI_INSTANCE_LEAF_NODE, value,
180                                          valueNs, curSchemaNode);
181         } else if (curSchemaNode instanceof ListSchemaNode) {
182             propNode = propNode.addChild(null, name, ns, MULTI_INSTANCE_NODE,
183                                          curSchemaNode);
184         } else {
185             propNode = propNode.addChild(name, ns, SINGLE_INSTANCE_NODE,
186                                          curSchemaNode);
187         }
188     }
189
190     /**
191      * Returns the namespace of the value namespace in case of identity ref.
192      *
193      * @param schemaNode schema node
194      * @param valNs      value name space
195      * @param nodeType   node type
196      * @return namespace of value namespace
197      * @throws SvcLogicException when namespace resolution fails for identityref
198      */
199     private Namespace getValueNs(SchemaNode schemaNode, String valNs,
200                                  NodeType nodeType) throws SvcLogicException {
201         Namespace ns = null;
202         if (valNs != null) {
203             TypeDefinition type;
204             if (schemaNode instanceof LeafSchemaNode) {
205                 type = ((LeafSchemaNode) schemaNode).getType();
206             } else {
207                 type = ((LeafListSchemaNode) schemaNode).getType();
208             }
209             TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
210             if (baseType instanceof IdentityrefTypeDefinition) {
211                 if (nodeType == null) {
212                     ns = getResolvedNamespace(null, valNs, getSchemaCtx(),
213                                               propNode);
214                 } else {
215                     ns = getResolvedNamespace(valNs, null, getSchemaCtx(),
216                                               propNode);
217                 }
218             }
219         }
220         return ns;
221     }
222
223     /**
224      * Validates that the node type from the data format matches with that of
225      * the corresponding schema node.
226      *
227      * @param type node type from the abstract data format
228      * @throws SvcLogicException when the node type is wrong
229      */
230     private void validateNodeType(NodeType type) throws SvcLogicException {
231         boolean verify;
232         switch (type) {
233             case SINGLE_INSTANCE_LEAF_NODE:
234                 verify = curSchemaNode instanceof LeafSchemaNode;
235                 break;
236
237             case MULTI_INSTANCE_LEAF_NODE:
238                 verify = curSchemaNode instanceof LeafListSchemaNode;
239                 break;
240
241             case MULTI_INSTANCE_NODE:
242                 verify = curSchemaNode instanceof ListSchemaNode;
243                 break;
244
245             case SINGLE_INSTANCE_NODE:
246                 verify = (!(curSchemaNode instanceof LeafSchemaNode) &&
247                         !(curSchemaNode instanceof LeafListSchemaNode) &&
248                         !(curSchemaNode instanceof ListSchemaNode));
249                 break;
250
251             default:
252                 throw new SvcLogicException(format(NODE_TYPE_ERR,
253                                                    type.toString()));
254         }
255         if (!verify) {
256             throw new SvcLogicException(format(DF_ERR, curSchemaNode
257                     .getQName().getLocalName(), type.toString()));
258         }
259     }
260
261     /**
262      * Returns true if the child schema is present with the name and
263      * namespace inside the current schema node, if present updates the
264      * current schema node; false otherwise.
265      *
266      * @param name      name of the child schema node
267      * @param namespace namespace of the child schema node
268      * @return returns true if the child schema is available; false otherwise
269      */
270     private boolean isChildPresent(String name, Namespace namespace) {
271         QName qname =  QName.create(namespace.moduleNs(),
272                                     Revision.of(namespace.revision()), name);
273         SchemaNode childNode = null;
274         if (curSchemaNode instanceof DataSchemaNode) {
275             Deque<DataSchemaNode> dataSchema = findSchemaNodeByNameAndNamespace(
276                     (DataSchemaNode) curSchemaNode, name, namespace.moduleNs());
277
278             if (dataSchema != null && !dataSchema.isEmpty()) {
279                 childNode = dataSchema.pop();
280             }
281
282             if (dataSchema != null && !dataSchema.isEmpty()) {
283                 childNode = findSchemaForChild(((ChoiceSchemaNode) childNode),
284                                                qname);
285             }
286
287         } else {
288             childNode = findDataChildSchemaByQName(curSchemaNode, qname);
289         }
290
291         if (childNode != null) {
292             curSchemaNode = childNode;
293             return true;
294         }
295         return false;
296     }
297 }