2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer;
23 import java.util.Collection;
24 import java.util.Deque;
25 import java.util.Iterator;
26 import java.util.Optional;
28 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
29 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
30 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.common.Revision;
33 import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
34 import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils;
35 import org.opendaylight.yangtools.yang.data.util.codec.IdentityCodecUtil;
36 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.Module;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 import static com.google.common.base.Preconditions.checkArgument;
47 import static java.lang.String.format;
48 import static java.util.regex.Pattern.quote;
49 import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier.toInstanceIdentifier;
52 * Represents utilities for properties node tree.
54 public final class MdsalPropertiesNodeUtils {
56 static final String COLON = ":";
58 static final String UNDERSCORE = "_";
60 static final String SLASH = "/";
62 static final String DOT_REGEX = "\\.";
64 private static final String INFO_MSG = "The %s formed is currently not" +
67 private static final String EXC_MSG = "Unable to form a formatted path";
70 * Logger for the Mdsal properties util class.
72 private static final Logger log = LoggerFactory.getLogger(
73 MdsalPropertiesNodeUtils.class);
75 private MdsalPropertiesNodeUtils() {
79 * Returns the index from multi instance property name.
81 * @param name name of the property
82 * @return index from multi instance property name
84 public static String getIndex(String name) {
85 return name.substring(name.indexOf("[") + 1,
90 * Returns the multi instance property name.
92 * @param name name of the property
93 * @return the multi instance property name
95 public static String getListName(String name) {
96 String[] s = name.split("\\[");
101 * Returns true if property is multi instance.
103 * @param name name of the property
104 * @return true if property is multi instance
106 public static boolean isListEntry(String name) {
107 String s[] = name.split("\\[");
112 * Returns name of the property after pruning namespace and
113 * index if the property is multi instance.
115 * @param name name of the property
116 * @return name of the property
118 static String resolveName(String name) {
119 String localName = getListName(name);
120 final int lastIndexOfColon = localName.lastIndexOf(":");
121 if (lastIndexOfColon != -1) {
122 localName = localName.substring(lastIndexOfColon + 1);
128 * Returns name of the property after pruning namespace and index if the
129 * property is multi instance by knowing the module name from namespace.
131 * @param ns namespace
132 * @param name name of the node
133 * @return resolved name
135 static String resolveName(Namespace ns, String name) {
136 String localName = getListName(name);
137 String modName = ns.moduleName();
138 if ((localName.contains(COLON) || localName.contains(UNDERSCORE))
139 && localName.startsWith(modName)) {
140 localName = localName.substring(modName.length()+1);
146 * Adds current node to parent's augmentation map.
148 * @param augSchema augment schema
149 * @param parent parent property node
150 * @param curNode current property node
152 public static void addToAugmentations(AugmentationSchemaNode augSchema,
153 PropertiesNode parent,
154 PropertiesNode curNode) {
155 Collection<PropertiesNode> childsFromAugmentation = parent
156 .augmentations().get(augSchema);
157 if (!childsFromAugmentation.isEmpty()) {
158 for (PropertiesNode pNode : childsFromAugmentation) {
159 if (pNode.name().equals(curNode.name())) {
164 parent.augmentations().put(augSchema, curNode);
169 * Returns augmented properties node if it is already
170 * added in properties tree.
172 * @param augSchema augmented schema node
173 * @param parent parent properties node
174 * @param name name of the properties
175 * @return augmented properties node if it is already added
177 public static PropertiesNode getAugmentationNode(
178 AugmentationSchemaNode augSchema,
179 PropertiesNode parent, String name) {
180 if (augSchema != null) {
181 Collection<PropertiesNode> childsFromAugmentation = parent
182 .augmentations().get(augSchema);
183 if (!childsFromAugmentation.isEmpty()) {
184 for (PropertiesNode pNode : childsFromAugmentation) {
185 if (pNode.name().equals(name)) {
195 * Creates uri with specified name and namespace.
197 * @param parent parent properties node
198 * @param name name of the node
199 * @param ns namespace of the node
200 * @return uri with specified name and namespace
202 public static String getUri(PropertiesNode parent, String name,
205 if (!(parent.namespace().moduleNs().equals(ns.moduleNs()))) {
206 uri = ns.moduleName() + ":" + name;
208 return parent.uri() + "." + uri;
212 * Creates new properties with specified parameters.
214 * @param name name of the properties node
215 * @param namespace namespace of the properties node
216 * @param uri uri of the properties node
217 * @param parent parent node
218 * @param appInfo application info
219 * @param type node type
220 * @return new properties node
222 public static PropertiesNode createNode(String name, Namespace namespace,
223 String uri, PropertiesNode parent,
224 Object appInfo, NodeType type) {
226 case SINGLE_INSTANCE_NODE:
227 return new SingleInstanceNode(name, namespace, uri, parent, appInfo, type);
228 case MULTI_INSTANCE_HOLDER_NODE:
229 return new ListHolderNode(name, namespace, uri, parent, appInfo, type);
230 case MULTI_INSTANCE_LEAF_HOLDER_NODE:
231 return new LeafListHolderNode(name, namespace, uri, parent, appInfo, type);
233 throw new RuntimeException("Invalid node type");
238 * Returns true if namespace is same as parent's namespace.
240 * @param parent parent property node
241 * @param curNode current property node
242 * @return true if namespace is same as parent namespace
244 public static boolean isNamespaceAsParent(PropertiesNode parent,
245 PropertiesNode curNode) {
246 return parent.namespace().moduleNs().equals(curNode.namespace().moduleNs());
250 * Returns the schema path holder with a formatted url and the instance
251 * identifier context from a given uri or the parameters from svc logic
254 * @param uri unformatted uri or parameter
255 * @param context schema context
256 * @return schema path holder
258 public static SchemaPathHolder getProcessedPath(String uri,
259 SchemaContext context) {
261 String uri1 = uri.replaceAll(UNDERSCORE, COLON);
263 InstanceIdentifierContext<?> id = toInstanceIdentifier(
264 uri1, context, null);
265 return new SchemaPathHolder(id, uri1);
266 } catch (IllegalArgumentException | RestconfDocumentedException
267 | NullPointerException e) {
268 return processNodesAndAppendPath(uri, context);
273 * Processes the nodes in the given uri and finds instance identifier
274 * context till it reaches the last node in uri. If its not able to find
275 * schema for the path, it appends the suffix part and puts it back in
278 * @param uri uri with underscore
279 * @param context schema context
280 * @return schema and path holder
282 private static SchemaPathHolder processNodesAndAppendPath(String uri,
283 SchemaContext context) {
286 SchemaPathHolder id = new SchemaPathHolder(null, "");
287 String[] uriParts = uri.split(SLASH);
289 if (uri.contains(UNDERSCORE)) {
290 sec = uri.substring(uriParts[0].length()+1);
292 for (int i = 0; i<uriParts.length; i++) {
295 id = processIdentifier(uriParts[i], context, actPath);
296 } catch (IllegalArgumentException e) {
297 id.setUri(actPath+ uriParts[i] + sec);
301 actPath = actPath + id.getUri() + SLASH;
302 if (sec.startsWith(SLASH)) {
303 sec = sec.replaceFirst(SLASH, "");
305 if (i+1 < uriParts.length) {
306 sec = sec.replaceFirst(quote(uriParts[i + 1]), "");
309 id.setUri(actPath.substring(0,actPath.length() - 1));
314 * Processes the schema and path holder for a given node in the path. It
315 * figures if the path is valid by replacing underscore in the node
316 * consecutively, till it finds the proper schema for the node.
318 * @param node node in the path
319 * @param context schema context
320 * @param prefix prefix for the node in the path
321 * @return schema and path holder
323 private static SchemaPathHolder processIdentifier(String node,
324 SchemaContext context,
327 String[] values = node.split(UNDERSCORE);
328 String val = values[0];
329 StringBuilder firstHalf = new StringBuilder();
330 String secondHalf = "";
331 if (node.contains(UNDERSCORE)) {
332 secondHalf = node.substring(values[0].length()+1);
334 InstanceIdentifierContext<?> id;
335 for (int i = 0; i< values.length-1; i++) {
337 val = firstHalf + val + COLON + secondHalf;
339 id = toInstanceIdentifier(prefix + val, context, null);
340 return new SchemaPathHolder(id, val);
341 } catch (IllegalArgumentException | RestconfDocumentedException |
342 NullPointerException e) {
343 log.info(format(INFO_MSG, val));
345 firstHalf.append(values[i]).append(UNDERSCORE);
346 secondHalf = secondHalf.replaceFirst(
347 values[i + 1] + UNDERSCORE,"");
349 val = val.replace(COLON,UNDERSCORE);
351 id = toInstanceIdentifier(prefix + val, context, null);
352 return new SchemaPathHolder(id, val);
353 } catch (IllegalArgumentException | RestconfDocumentedException |
354 NullPointerException e1) {
355 throw new IllegalArgumentException(EXC_MSG, e1);
360 * Returns the namespace of the given node name. If the node name is
361 * separated by colon, the it splits with colon and forms the namespace.
362 * If the node name is formed with underscore, then it splits the node
363 * name consecutively to figure out the proper module name.
365 * @param childName node name
366 * @param ctx schema context
367 * @param parent parent properties node
368 * @param curSchema current schema
369 * @return namespace of the given node
371 static Namespace getNamespace(String childName, SchemaContext ctx,
372 PropertiesNode parent, SchemaNode curSchema) {
374 Namespace parentNs = parent.namespace();
375 Namespace ns = new Namespace(parentNs.moduleName(),
376 parentNs.moduleNs(), parentNs.revision());
377 int lastIndexOfColon = childName.lastIndexOf(COLON);
378 if (lastIndexOfColon != -1) {
379 String moduleName = childName.substring(0, lastIndexOfColon);
380 childName = childName.substring(lastIndexOfColon+1);
381 Namespace ns1 = getNs(moduleName, ctx);
387 SchemaNode child = getChildSchemaNode(curSchema, childName, ns);
389 if (child == null && childName.contains(UNDERSCORE)) {
390 String[] children = childName.split(UNDERSCORE);
391 String second = childName.substring(children[0].length() + 1);
392 StringBuilder first = new StringBuilder();
394 for (int i =0; i< children.length; i++) {
395 String moduleName = first + children[i];
396 Namespace newNs = getNs(moduleName, ctx);
400 first.append(children[i]).append(UNDERSCORE);
401 if (i + 1 < children.length) {
402 second = second.replaceFirst(
403 children[i + 1] + UNDERSCORE, "");
412 * Returns the namespace by finding the given module in the schema context.
414 * @param modName module name
415 * @param ctx schema context
416 * @return namespace of the given node name
418 private static Namespace getNs(String modName, SchemaContext ctx) {
419 Iterator<Module> it = ctx.findModules(modName).iterator();
421 Module m = it.next();
422 return new Namespace(modName, m.getQNameModule().getNamespace(),
423 getRevision(m.getRevision()));
429 * Returns child schema node.
431 * @param curSchema current schema node
432 * @param name name of the property
433 * @param namespace namespace of the property
434 * @return child schema node
436 public static SchemaNode getChildSchemaNode(SchemaNode curSchema,
438 Namespace namespace) {
439 if (namespace == null) {
443 QName qname = QName.create(namespace.moduleNs(),
444 Revision.of(namespace.revision()), name);
446 // YANG RPC will not be instance of DataSchemaNode
447 if (curSchema instanceof DataSchemaNode) {
448 Deque<DataSchemaNode> schemaNodeDeque = ParserStreamUtils.
449 findSchemaNodeByNameAndNamespace(((DataSchemaNode)
450 curSchema), name, namespace.moduleNs());
451 if (schemaNodeDeque.isEmpty()) {
452 // could not find schema node
456 DataSchemaNode schemaNode = schemaNodeDeque.pop();
457 if (schemaNodeDeque.isEmpty()){
462 // node is child of Choice/case
463 return SchemaUtils.findSchemaForChild(((ChoiceSchemaNode) schemaNode),
466 return SchemaUtils.findDataChildSchemaByQName(curSchema, qname);
471 * Returns the property node type.
473 * @param index current index
474 * @param length length of the properties
475 * @param name name of the property
476 * @return the property node type
478 public static NodeType getNodeType(int index, int length, String name) {
479 if (index == length-1) {
480 return (isListEntry(name) ? NodeType.MULTI_INSTANCE_LEAF_NODE :
481 NodeType.SINGLE_INSTANCE_LEAF_NODE);
483 return (isListEntry(name) ? NodeType.MULTI_INSTANCE_NODE :
484 NodeType.SINGLE_INSTANCE_NODE);
489 * Returns revision in string.
491 * @param r YANG revision
492 * @return revision in string
494 public static String getRevision(Optional<Revision> r) {
495 return (r.isPresent()) ? r.get().toString() : null;
499 * Returns value namespace for leaf value.
501 * @param value value of the leaf
502 * @param ctx schema context
503 * @return value namespace
504 * @throws SvcLogicException if identity/module could not be found
506 static Namespace getValueNamespace(String value,
508 throws SvcLogicException {
509 String prefix = getPrefixFromValue(value);
510 if (prefix == null) {
514 IdentitySchemaNode id = IdentityCodecUtil.parseIdentity(value,
517 final Iterator<Module> modules = ctx.findModules(prefix).iterator();
518 checkArgument(modules.hasNext(), "Could not find " +
519 "module %s", prefix);
520 return modules.next().getQNameModule();
524 throw new SvcLogicException("Could not find identity");
527 return getModuleNamespace(id.getQName(), ctx);
530 private static String getPrefixFromValue(String value) {
531 int lastIndexOfColon = value.lastIndexOf(":");
532 if (lastIndexOfColon != -1) {
533 return value.substring(0, lastIndexOfColon);
539 * Returns module namespace from a given qName.
541 * @param qName qName of a node
542 * @param ctx schema context
543 * @return module namespace of the node
544 * @throws SvcLogicException when the module is not available
546 public static Namespace getModuleNamespace(QName qName, SchemaContext ctx)
547 throws SvcLogicException {
548 Optional<Module> module = ctx.findModule(qName.getModule());
549 if (!module.isPresent()) {
550 throw new SvcLogicException("Could not find module node");
552 Module m = module.get();
553 return new Namespace(m.getName(), m.getQNameModule().getNamespace(),
554 getRevision(m.getRevision()));
557 static String getParsedValue(Namespace valNs, String value) {
558 if (valNs != null && value.contains(":")) {
559 String[] valArr = value.split(":");