blob: 6ac031e90e63e395c341040cb67ff303ac580d02 [file] [log] [blame]
Bharat saraswal49120772017-03-10 17:06:10 +05301/*
Brian O'Connor72b2df22017-08-03 18:48:28 -07002 * Copyright 2017-present Open Networking Foundation
Bharat saraswal49120772017-03-10 17:06:10 +05303 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.yang.runtime.impl;
17
18import org.onosproject.yang.compiler.datamodel.YangAugment;
19import org.onosproject.yang.compiler.datamodel.YangAugmentableNode;
janani bfe71e172017-09-01 18:40:35 +053020import org.onosproject.yang.compiler.datamodel.YangInput;
Bharat saraswal49120772017-03-10 17:06:10 +053021import org.onosproject.yang.compiler.datamodel.YangLeaf;
22import org.onosproject.yang.compiler.datamodel.YangLeafList;
23import org.onosproject.yang.compiler.datamodel.YangLeavesHolder;
24import org.onosproject.yang.compiler.datamodel.YangList;
25import org.onosproject.yang.compiler.datamodel.YangNode;
janani bfe71e172017-09-01 18:40:35 +053026import org.onosproject.yang.compiler.datamodel.YangOutput;
Bharat saraswal49120772017-03-10 17:06:10 +053027import org.onosproject.yang.compiler.datamodel.YangRpc;
28import org.onosproject.yang.compiler.datamodel.YangSchemaNode;
janani bd6361c92017-06-19 15:45:55 +053029import org.onosproject.yang.compiler.datamodel.YangSchemaNodeType;
janani b59599d42017-07-18 17:28:42 +053030import org.onosproject.yang.compiler.datamodel.YangType;
Bharat saraswal49120772017-03-10 17:06:10 +053031import org.onosproject.yang.model.AtomicPath;
32import org.onosproject.yang.model.ModelObjectId;
33import org.onosproject.yang.model.MultiInstanceLeaf;
34import org.onosproject.yang.model.MultiInstanceNode;
35import org.onosproject.yang.model.ResourceId;
36import org.onosproject.yang.model.SingleInstanceLeaf;
37
38import java.util.Iterator;
39import java.util.List;
40import java.util.Set;
41import java.util.regex.Pattern;
42
janani bd6361c92017-06-19 15:45:55 +053043import static org.onosproject.yang.compiler.datamodel.YangSchemaNodeType.YANG_AUGMENT_NODE;
Bharat saraswal49120772017-03-10 17:06:10 +053044import static org.onosproject.yang.compiler.datamodel.YangSchemaNodeType.YANG_NON_DATA_NODE;
45import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.nonEmpty;
46import static org.onosproject.yang.compiler.utils.io.impl.YangIoUtils.getCamelCase;
Gaurav Agrawald829db32017-05-13 15:39:16 +053047import static org.onosproject.yang.runtime.RuntimeHelper.DEFAULT_CAPS;
48import static org.onosproject.yang.runtime.RuntimeHelper.PERIOD;
49import static org.onosproject.yang.runtime.RuntimeHelper.getCapitalCase;
janani b59599d42017-07-18 17:28:42 +053050import static org.onosproject.yang.runtime.impl.ModelConverterUtil.fetchPackage;
51import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getAttributeOfObject;
52import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getObjFromType;
Bharat saraswal49120772017-03-10 17:06:10 +053053
54/**
55 * Converts model object identifier to resource identifier.
56 */
57class ModIdToRscIdConverter {
58
59 /**
janani b59599d42017-07-18 17:28:42 +053060 * Model registry.
61 */
62 private final DefaultYangModelRegistry reg;
63 /**
Bharat saraswal49120772017-03-10 17:06:10 +053064 * Schema node with respect to the last atomic path in model object
65 * identifier. in case of leaf node as last atomic path last index node
66 * will be leaf's parent node.
67 */
68 private YangSchemaNode lastIndexNode;
Bharat saraswal49120772017-03-10 17:06:10 +053069 /**
70 * Flag to know if model object identifier contains leaf identifier.
71 */
72 private boolean isMoIdWithLeaf;
Bharat saraswal49120772017-03-10 17:06:10 +053073 /**
74 * Flag is true if rpc is added in branch point schema of resource
75 * identifier.
76 */
77 private boolean isRpcAdded = true;
Bharat saraswal49120772017-03-10 17:06:10 +053078 /**
Bharat saraswalad7d8e72017-03-15 10:52:14 +053079 * Flag is true if we have found module node using input/output packages.
80 */
81 private boolean isInputOrOutput;
82
83 /**
Bharat saraswal49120772017-03-10 17:06:10 +053084 * Creates an instance of converter.
85 *
86 * @param registry model registry
87 */
88 ModIdToRscIdConverter(DefaultYangModelRegistry registry) {
89 reg = registry;
90 }
91
92
93 /**
sonugupta-huawei99c0a012017-12-23 00:44:15 +053094 * Fetch resource identifier builder from model object identifier.
Bharat saraswal49120772017-03-10 17:06:10 +053095 *
96 * @param id model object identifier
sonugupta-huawei99c0a012017-12-23 00:44:15 +053097 * @return resource identifier builder from model object identifier
Bharat saraswal49120772017-03-10 17:06:10 +053098 */
sonugupta-huawei99c0a012017-12-23 00:44:15 +053099 ResourceId.Builder fetchResourceId(ModelObjectId id) {
Bharat saraswal49120772017-03-10 17:06:10 +0530100
101 ResourceId.Builder rid = ResourceId.builder().addBranchPointSchema("/", null);
102 if (id == null || id.atomicPaths().isEmpty()) {
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530103 return rid;
Bharat saraswal49120772017-03-10 17:06:10 +0530104 }
105
106 List<AtomicPath> paths = id.atomicPaths();
107 AtomicPath path = paths.get(0);
108
109 //If first element in model id contains only leaf/leaf-list then it
110 // will be for module so in that case resource identifier will be
111 // till module's leaf only.
112 if (path instanceof SingleInstanceLeaf ||
113 path instanceof MultiInstanceLeaf) {
114 isMoIdWithLeaf = true;
115 Object identifier;
116 if (path instanceof SingleInstanceLeaf) {
117 identifier = ((SingleInstanceLeaf) path).leafIdentifier();
118 } else {
119 identifier = ((MultiInstanceLeaf) path).leafIdentifier();
120 }
121 lastIndexNode = fetchModNodeFromLeaf(identifier.getClass().getName());
122 if (lastIndexNode != null) {
123 handleLeafInRid(lastIndexNode, id, rid, path);
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530124 return rid;
Bharat saraswal49120772017-03-10 17:06:10 +0530125 }
126 }
127
128 return convertToResourceId(id, fetchModuleNode(fetchPackage(path)),
129 rid);
130 }
131
132 /**
133 * Returns module node from leaf package.
134 *
135 * @param pkg leaf identifier package
136 * @return module node from leaf package
137 */
138 YangSchemaNode fetchModNodeFromLeaf(String pkg) {
139 String[] array = pkg.split(Pattern.quote("$"));
Bharat saraswal726194f2017-04-12 14:42:53 +0530140 return reg.getForRegClassName(array[0]);
Bharat saraswal49120772017-03-10 17:06:10 +0530141 }
142
143 /**
144 * Takes the first element in model object id and then uses it to fetch
145 * the module schema fetchNode from model registry.
146 *
147 * @param pkg package for child node
Yuta HIGUCHIcf489c32017-12-20 20:39:05 -0800148 * @return first matching module schema
Bharat saraswal49120772017-03-10 17:06:10 +0530149 */
150 YangSchemaNode fetchModuleNode(String pkg) {
151 YangSchemaNode modNode;
152 StringBuilder modPkg = new StringBuilder();
153
154 //In other case we need to find the package
155 // of module fetchNode from the given fetchNode's package.
156 String[] strArray = pkg.split(Pattern.quote(PERIOD));
157 int i = 0;
158 while (i <= strArray.length - 3) {
159 modPkg.append(strArray[i]).append(PERIOD);
160 i++;
161 }
162
163 //If path contains input fetchNode class then in that case if we add
164 // current modePkg will be the correct package for module fetchNode
165 // because the next string will be rpc name in received from fetch
166 // package method.
167 modPkg.deleteCharAt(modPkg.lastIndexOf(PERIOD));
Bharat saraswal726194f2017-04-12 14:42:53 +0530168 YangNode node = (YangNode) reg.getForRegClassQualifiedName(modPkg.toString(),
169 true);
Bharat saraswal49120772017-03-10 17:06:10 +0530170 if (node != null) {
171 modNode = node;
172 //in this case we should update the lastIndexNode for object to
173 // data fetchNode conversion. because we need to create the data fetchNode
174 // with the input fetchNode's data
175 node = node.getChild();
176 while (node != null) {
janani bd6361c92017-06-19 15:45:55 +0530177 YangSchemaNodeType type = node.getYangSchemaNodeType();
178 if (type != YANG_NON_DATA_NODE && type != YANG_AUGMENT_NODE &&
179 node.getJavaAttributeName().toLowerCase()
180 .equals(strArray[i])) {
Bharat saraswal49120772017-03-10 17:06:10 +0530181 //last index fetchNode will be input fetchNode.
182 lastIndexNode = node.getChild();
183 break;
184 }
185 node = node.getNextSibling();
186 }
janani bfe71e172017-09-01 18:40:35 +0530187 if (lastIndexNode instanceof YangInput ||
188 lastIndexNode instanceof YangOutput) {
189 isInputOrOutput = true;
190 }
Bharat saraswal49120772017-03-10 17:06:10 +0530191 } else {
192 modPkg.append(PERIOD);
193 //In this case this package will be of module fetchNode.
194 modPkg.append(strArray[i]);
Bharat saraswal726194f2017-04-12 14:42:53 +0530195 modNode = reg.getForRegClassQualifiedName(modPkg.toString(), false);
Bharat saraswal49120772017-03-10 17:06:10 +0530196 }
197 return modNode;
198 }
199
200 /**
201 * Converts model object identifier to resource identifier.
202 *
203 * @param id model object identifier
204 * @param builder resource id builder
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530205 * @return resource identifier builder
Bharat saraswal49120772017-03-10 17:06:10 +0530206 */
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530207 private ResourceId.Builder convertToResourceId(ModelObjectId id, YangSchemaNode
Bharat saraswal49120772017-03-10 17:06:10 +0530208 modNode, ResourceId.Builder builder) {
209 List<AtomicPath> paths = id.atomicPaths();
210 Iterator<AtomicPath> it = paths.iterator();
211 AtomicPath path;
212 String pkg;
213 YangSchemaNode curNode = modNode;
214 YangSchemaNode preNode = null;
215 YangNode tempNode;
216 while (it.hasNext()) {
217 path = it.next();
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700218 try {
219 //Get the java package for given atomic path. this package will
220 // be java package for schema node
221 pkg = fetchPackage(path);
222 if (curNode instanceof YangAugmentableNode) {
223 tempNode = fetchFromAugment((YangNode) curNode, pkg, builder);
224 if (tempNode != null) {
225 curNode = tempNode;
226 } else {
227 //fetch the node for which model object identifier
228 // contains the atomic path.
229 curNode = fetchNode(((YangNode) curNode).getChild(), pkg, builder);
230 }
Bharat saraswal49120772017-03-10 17:06:10 +0530231 } else {
Bharat saraswal49120772017-03-10 17:06:10 +0530232 curNode = fetchNode(((YangNode) curNode).getChild(), pkg, builder);
233 }
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700234 //if the current node is null and atomic path list contains
235 // another node, then there is possibility that its a leaf node.
236 if (curNode == null && paths.indexOf(path) == paths.size() - 1) {
237 //check leaf nodes in previous nodes.
238 handleLeafInRid(preNode, id, builder, path);
239 } else if (curNode != null) {
Bharat saraswal49120772017-03-10 17:06:10 +0530240
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700241 builder.addBranchPointSchema(curNode.getName(), curNode
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530242 .getNameSpace().getModuleNamespace());
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700243 //list node can have key leaf in it. so resource identifier
244 // should have key leaves also.
245 if (curNode instanceof YangList) {
246 YangList list = (YangList) curNode;
247 MultiInstanceNode mil = (MultiInstanceNode) path;
248 Object keysObj = mil.key();
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530249 if (keysObj != null) {
250 Set<String> keys = list.getKeyLeaf();
251 for (String key : keys) {
252 Object obj = getKeyObject(keysObj, key, list);
253 builder.addKeyLeaf(key, list.getNameSpace()
254 .getModuleNamespace(), obj);
255 }
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700256 }
Bharat saraswal49120772017-03-10 17:06:10 +0530257 }
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700258 } else {
Yuta HIGUCHIe0d8b082017-08-30 17:24:41 -0700259 throw new ModelConverterException("invalid model object id." + id);
Bharat saraswal49120772017-03-10 17:06:10 +0530260 }
Yuta HIGUCHI3b61b1b2017-08-29 16:29:53 -0700261 preNode = curNode;
262 } catch (Exception e) {
Yuta HIGUCHIe0d8b082017-08-30 17:24:41 -0700263 throw new ModelConverterException("Encountered an Exception processing " + path, e);
Bharat saraswal49120772017-03-10 17:06:10 +0530264 }
Bharat saraswal49120772017-03-10 17:06:10 +0530265 }
266 if (!isMoIdWithLeaf) {
267 // last node with respect to the last class in model object
268 // identifier. model object will be an object for last index node.
269 lastIndexNode = curNode;
270 }
sonugupta-huawei99c0a012017-12-23 00:44:15 +0530271 builder.appInfo(curNode);
272 return builder;
Bharat saraswal49120772017-03-10 17:06:10 +0530273 }
274
275 private void handleLeafInRid(YangSchemaNode preNode, ModelObjectId id,
276 ResourceId.Builder builder, AtomicPath path) {
277 //check leaf nodes in previous nodes.
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530278 String pkg = fetchPackage(path);
janani b59599d42017-07-18 17:28:42 +0530279 YangSchemaNode curNode = fetchLeaf(preNode, pkg, false);
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530280 if (curNode == null) {
281 if (preNode instanceof YangAugmentableNode) {
282 List<YangAugment> augments = ((YangAugmentableNode) preNode)
283 .getAugmentedInfoList();
284 for (YangAugment augment : augments) {
janani b59599d42017-07-18 17:28:42 +0530285 curNode = fetchLeaf(augment, pkg, false);
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530286 if (curNode != null) {
287 break;
288 }
289 }
290 }
291 }
Bharat saraswal49120772017-03-10 17:06:10 +0530292 if (curNode == null) {
Yuta HIGUCHIe0d8b082017-08-30 17:24:41 -0700293 throw new ModelConverterException("invalid model object id." + id);
Bharat saraswal49120772017-03-10 17:06:10 +0530294 }
295 isMoIdWithLeaf = true;
296 if (curNode instanceof YangLeaf) {
297 //leaf should be added as a branch point schema
298 builder.addBranchPointSchema(curNode.getName(), curNode
299 .getNameSpace().getModuleNamespace());
300 } else {
301 // leaf list should be added as leaf list branch point
302 // schema with its value added to it.
janani b59599d42017-07-18 17:28:42 +0530303 YangType<?> type = ((YangLeafList) curNode).getDataType();
Bharat saraswal49120772017-03-10 17:06:10 +0530304 Object val = ((MultiInstanceLeaf) path).value();
janani b59599d42017-07-18 17:28:42 +0530305 val = getObjFromType(preNode, path, curNode, "value", val, type);
Bharat saraswal49120772017-03-10 17:06:10 +0530306 builder.addLeafListBranchPoint(curNode.getName(), curNode
307 .getNameSpace().getModuleNamespace(), val);
308 }
309 }
310
311 private String getJavaPkg(YangNode node) {
312 return node.getJavaPackage() + PERIOD + DEFAULT_CAPS +
313 getCapitalCase(node.getJavaClassNameOrBuiltInType());
314 }
315
316 /**
317 * Returns augment node in case node is augmented.
318 *
319 * @param curNode current node
320 * @param pkg java package
321 * @return augment node
322 */
323 private YangNode fetchFromAugment(YangNode curNode, String pkg,
324 ResourceId.Builder builder) {
325 YangNode tempNode;
326 if (curNode != null) {
327 if (curNode instanceof YangAugmentableNode) {
328 List<YangAugment> augments = ((YangAugmentableNode) curNode)
329 .getAugmentedInfoList();
330 if (nonEmpty(augments)) {
331 //fetch augment node from augment list and returns it.
332 for (YangAugment augment : augments) {
333 //process augment's child nodes.
334 tempNode = fetchNode(augment.getChild(), pkg, builder);
335 if (tempNode != null) {
336 return tempNode;
337 }
338 }
339 }
340 }
341 }
342 return null;
343 }
344
345 /**
346 * Returns key value from the key class object.
347 *
348 * @param keys key class object
349 * @param keyName key name
350 * @return key value
351 */
352 private Object getKeyValue(Object keys, String keyName) {
353 try {
354 return getAttributeOfObject(keys, getCamelCase(keyName, null));
355 } catch (NoSuchMethodException e) {
Yuta HIGUCHIe0d8b082017-08-30 17:24:41 -0700356 throw new ModelConverterException("invalid key value in model id for list" +
Yuta HIGUCHI52724f52017-12-28 17:26:46 -0800357 "." + keys.getClass().getName(), e);
Bharat saraswal49120772017-03-10 17:06:10 +0530358 }
359 }
360
361 /**
362 * Returns YANG fetchNode for given package.
363 *
364 * @param node YANG fetchNode
365 * @param pkg package
366 * @param builder resource identifier builder
367 * @return YANG fetchNode
368 */
369 private YangNode fetchNode(YangNode node, String pkg,
370 ResourceId.Builder builder) {
371 String java;
372 while (node != null) {
373 //compare the java package with the package found in model object
374 // identifier.
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530375 if (node.getYangSchemaNodeType() != YANG_NON_DATA_NODE) {
Bharat saraswal49120772017-03-10 17:06:10 +0530376 java = getJavaPkg(node);
377 if (java.equals(pkg)) {
378 return node;
379 } else if (node instanceof YangRpc) {
380 // in case of a input node rpc also needs to be added to
381 // resource identifier
382 if (isRpcAdded) {
383 isRpcAdded = false;
384 builder.addBranchPointSchema(node.getName(), node.getNameSpace()
385 .getModuleNamespace());
386 }
387 // node will become input node
388 node = node.getChild();
389 } else {
390 // check in next sibling node
391 node = node.getNextSibling();
392 }
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530393 } else {
394 // check in next sibling node
395 node = node.getNextSibling();
Bharat saraswal49120772017-03-10 17:06:10 +0530396 }
397 }
398 return null;
399 }
400
janani b59599d42017-07-18 17:28:42 +0530401 private YangSchemaNode fetchLeaf(YangSchemaNode node, String name,
402 boolean isSchemaName) {
Bharat saraswal49120772017-03-10 17:06:10 +0530403 YangLeavesHolder holder = (YangLeavesHolder) node;
404 List<YangLeaf> leaves = holder.getListOfLeaf();
janani b59599d42017-07-18 17:28:42 +0530405 String lName;
Bharat saraswal49120772017-03-10 17:06:10 +0530406 // check if the names is equal to any of the leaf/leaf-list nodes.
407 if (nonEmpty(leaves)) {
408 for (YangLeaf leaf : leaves) {
janani b59599d42017-07-18 17:28:42 +0530409 lName = leaf.getName();
410 if (!isSchemaName) {
411 lName = leaf.getJavaAttributeName().toLowerCase();
412 }
413 if (lName.equals(name)) {
Bharat saraswal49120772017-03-10 17:06:10 +0530414 return leaf;
415 }
416 }
417 }
418 List<YangLeafList> leafLists = holder.getListOfLeafList();
419 if (nonEmpty(leafLists)) {
janani b59599d42017-07-18 17:28:42 +0530420 for (YangLeafList ll : leafLists) {
421 lName = ll.getName();
422 if (!isSchemaName) {
423 lName = ll.getJavaAttributeName().toLowerCase();
424 }
425 if (lName.equals(name)) {
426 return ll;
Bharat saraswal49120772017-03-10 17:06:10 +0530427 }
428 }
429 }
430 return null;
431 }
432
433 /**
434 * Returns last index node for the last index atomic path of model object
435 * identifier.
436 *
437 * @return schema node
438 */
439 YangSchemaNode getLastIndexNode() {
440 return lastIndexNode;
441 }
442
443 /**
444 * Returns true if model object identifier contains leaf.
445 *
446 * @return true if model object identifier contains leaf
447 */
448 boolean isMoIdWithLeaf() {
449 return isMoIdWithLeaf;
450 }
Bharat saraswalad7d8e72017-03-15 10:52:14 +0530451
452 /**
453 * Returns true if module node is found using input/output packages.
454 *
455 * @return true if module node is found using input/output packages
456 */
457 boolean isInputOrOutput() {
458 return isInputOrOutput;
459 }
janani b59599d42017-07-18 17:28:42 +0530460
461 /**
462 * Returns the key leaf's processed object to be present in the resource id.
463 *
464 * @param keysObj list of keys object
465 * @param key leaf key object
466 * @param list YANG list
467 * @return processed object
468 */
469 private Object getKeyObject(Object keysObj, String key, YangList list) {
470 Object keyObj = getKeyValue(keysObj, key);
471 YangSchemaNode leaf = fetchLeaf(list, key, true);
472
473 if (leaf == null) {
474 List<YangAugment> augment = list.getAugmentedInfoList();
475 for (YangAugment a : augment) {
476 leaf = fetchLeaf(a, key, true);
477 if (leaf != null) {
478 break;
479 }
480 }
481 }
482 if (leaf == null) {
Yuta HIGUCHIe0d8b082017-08-30 17:24:41 -0700483 throw new ModelConverterException(
janani b59599d42017-07-18 17:28:42 +0530484 "The specified key " + key + " is not present in the " +
485 "YANG schema node.");
486 }
487 YangType<?> type;
488 if (leaf instanceof YangLeaf) {
489 type = ((YangLeaf) leaf).getDataType();
490 } else {
491 type = ((YangLeafList) leaf).getDataType();
492 }
493 return getObjFromType(list, keysObj, leaf, key, keyObj, type);
494 }
Bharat saraswal49120772017-03-10 17:06:10 +0530495}