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.AnyXmlSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 import static com.google.common.base.Preconditions.checkArgument;
48 import static java.lang.String.format;
49 import static java.util.regex.Pattern.quote;
50 import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier.toInstanceIdentifier;
53 * Represents utilities for properties node tree.
55 public final class MdsalPropertiesNodeUtils {
57 static final String COLON = ":";
59 static final String UNDERSCORE = "_";
61 static final String SLASH = "/";
63 static final String DOT_REGEX = "\\.";
65 private static final String INFO_MSG = "The %s formed is currently not" +
68 private static final String EXC_MSG = "Unable to form a formatted path";
71 * Logger for the Mdsal properties util class.
73 private static final Logger log = LoggerFactory.getLogger(
74 MdsalPropertiesNodeUtils.class);
76 private MdsalPropertiesNodeUtils() {
80 * Returns the index from multi instance property name.
82 * @param name name of the property
83 * @return index from multi instance property name
85 public static String getIndex(String name) {
86 return name.substring(name.indexOf("[") + 1,
91 * Returns the multi instance property name.
93 * @param name name of the property
94 * @return the multi instance property name
96 public static String getListName(String name) {
97 String[] s = name.split("\\[");
102 * Returns true if property is multi instance.
104 * @param name name of the property
105 * @return true if property is multi instance
107 public static boolean isListEntry(String name) {
108 String s[] = name.split("\\[");
113 * Returns name of the property after pruning namespace and
114 * index if the property is multi instance.
116 * @param name name of the property
117 * @return name of the property
119 static String resolveName(String name) {
120 String localName = getListName(name);
121 final int lastIndexOfColon = localName.lastIndexOf(":");
122 if (lastIndexOfColon != -1) {
123 localName = localName.substring(lastIndexOfColon + 1);
129 * Returns name of the property after pruning namespace and index if the
130 * property is multi instance by knowing the module name from namespace.
132 * @param ns namespace
133 * @param name name of the node
134 * @return resolved name
136 static String resolveName(Namespace ns, String name) {
137 String localName = getListName(name);
138 String modName = ns.moduleName();
139 if ((localName.contains(COLON) || localName.contains(UNDERSCORE))
140 && localName.startsWith(modName)) {
141 localName = localName.substring(modName.length()+1);
147 * Adds current node to parent's augmentation map.
149 * @param augSchema augment schema
150 * @param parent parent property node
151 * @param curNode current property node
153 public static void addToAugmentations(AugmentationSchemaNode augSchema,
154 PropertiesNode parent,
155 PropertiesNode curNode) {
156 Collection<PropertiesNode> childsFromAugmentation = parent
157 .augmentations().get(augSchema);
158 if (!childsFromAugmentation.isEmpty()) {
159 for (PropertiesNode pNode : childsFromAugmentation) {
160 if (pNode.name().equals(curNode.name())) {
165 parent.augmentations().put(augSchema, curNode);
170 * Returns augmented properties node if it is already
171 * added in properties tree.
173 * @param augSchema augmented schema node
174 * @param parent parent properties node
175 * @param name name of the properties
176 * @return augmented properties node if it is already added
178 public static PropertiesNode getAugmentationNode(
179 AugmentationSchemaNode augSchema,
180 PropertiesNode parent, String name) {
181 if (augSchema == null) {
185 Collection<PropertiesNode> childsFromAugmentation = parent
186 .augmentations().get(augSchema);
187 if (!childsFromAugmentation.isEmpty()) {
188 for (PropertiesNode pNode : childsFromAugmentation) {
189 if (pNode.name().equals(name)) {
199 * Creates uri with specified name and namespace.
201 * @param parent parent properties node
202 * @param name name of the node
203 * @param ns namespace of the node
204 * @return uri with specified name and namespace
206 public static String getUri(PropertiesNode parent, String name,
209 if (!(parent.namespace().moduleNs().equals(ns.moduleNs()))) {
210 uri = ns.moduleName() + ":" + name;
212 return parent.uri() + "." + uri;
216 * Creates new properties with specified parameters.
218 * @param name name of the properties node
219 * @param namespace namespace of the properties node
220 * @param uri uri of the properties node
221 * @param parent parent node
222 * @param appInfo application info
223 * @param type node type
224 * @return new properties node
225 * @throws SvcLogicException exception while creating properties node
227 public static PropertiesNode createNode(String name, Namespace namespace,
228 String uri, PropertiesNode parent,
229 Object appInfo, NodeType type)
230 throws SvcLogicException {
232 case SINGLE_INSTANCE_NODE:
233 return new SingleInstanceNode(name, namespace, uri, parent, appInfo, type);
234 case MULTI_INSTANCE_HOLDER_NODE:
235 return new ListHolderNode(name, namespace, uri, parent, appInfo, type);
236 case MULTI_INSTANCE_LEAF_HOLDER_NODE:
237 return new LeafListHolderNode(name, namespace, uri, parent, appInfo, type);
239 throw new SvcLogicException("Invalid node type " + type);
244 * Returns true if namespace is same as parent's namespace.
246 * @param parent parent property node
247 * @param curNode current property node
248 * @return true if namespace is same as parent namespace
250 public static boolean isNamespaceAsParent(PropertiesNode parent,
251 PropertiesNode curNode) {
252 return parent.namespace().moduleNs().equals(curNode.namespace().moduleNs());
256 * Returns the schema path holder with a formatted url and the instance
257 * identifier context from a given uri or the parameters from svc logic
260 * @param uri unformatted uri or parameter
261 * @param context schema context
262 * @return schema path holder
264 public static SchemaPathHolder getProcessedPath(String uri,
265 SchemaContext context) {
267 String uri1 = uri.replaceAll(UNDERSCORE, COLON);
269 InstanceIdentifierContext<?> id = toInstanceIdentifier(
270 uri1, context, null);
271 return new SchemaPathHolder(id, uri1);
272 } catch (IllegalArgumentException | RestconfDocumentedException
273 | NullPointerException e) {
274 log.info("Exception while converting uri to instance identifier" +
275 " context. Process each node in uri to get instance identifier" +
277 return processNodesAndAppendPath(uri, context);
282 * Processes the nodes in the given uri and finds instance identifier
283 * context till it reaches the last node in uri. If its not able to find
284 * schema for the path, it appends the suffix part and puts it back in
287 * @param uri uri with underscore
288 * @param context schema context
289 * @return schema and path holder
291 private static SchemaPathHolder processNodesAndAppendPath(String uri,
292 SchemaContext context) {
295 SchemaPathHolder id = new SchemaPathHolder(null, "");
296 String[] uriParts = uri.split(SLASH);
298 if (uri.contains(UNDERSCORE)) {
299 sec = uri.substring(uriParts[0].length()+1);
301 for (int i = 0; i<uriParts.length; i++) {
304 id = processIdentifier(uriParts[i], context, actPath);
305 } catch (IllegalArgumentException e) {
306 log.info(format(EXC_MSG, e));
307 id.setUri(actPath+ uriParts[i] + sec);
311 actPath = actPath + id.getUri() + SLASH;
312 if (sec.startsWith(SLASH)) {
313 sec = sec.replaceFirst(SLASH, "");
315 if (i+1 < uriParts.length) {
316 sec = sec.replaceFirst(quote(uriParts[i + 1]), "");
319 id.setUri(actPath.substring(0,actPath.length() - 1));
324 * Processes the schema and path holder for a given node in the path. It
325 * figures if the path is valid by replacing underscore in the node
326 * consecutively, till it finds the proper schema for the node.
328 * @param node node in the path
329 * @param context schema context
330 * @param prefix prefix for the node in the path
331 * @return schema and path holder
333 private static SchemaPathHolder processIdentifier(String node,
334 SchemaContext context,
337 String[] values = node.split(UNDERSCORE);
338 String val = values[0];
339 StringBuilder firstHalf = new StringBuilder();
340 String secondHalf = "";
341 if (node.contains(UNDERSCORE)) {
342 secondHalf = node.substring(values[0].length()+1);
344 InstanceIdentifierContext<?> id;
345 for (int i = 0; i< values.length-1; i++) {
347 val = firstHalf + val + COLON + secondHalf;
349 id = toInstanceIdentifier(prefix + val, context, null);
350 return new SchemaPathHolder(id, val);
351 } catch (IllegalArgumentException | RestconfDocumentedException |
352 NullPointerException e) {
353 log.info(format(INFO_MSG, val, e));
355 firstHalf.append(values[i]).append(UNDERSCORE);
356 secondHalf = secondHalf.replaceFirst(
357 values[i + 1] + UNDERSCORE,"");
359 val = val.replace(COLON,UNDERSCORE);
361 id = toInstanceIdentifier(prefix + val, context, null);
362 return new SchemaPathHolder(id, val);
363 } catch (IllegalArgumentException | RestconfDocumentedException |
364 NullPointerException e1) {
365 throw new IllegalArgumentException(EXC_MSG, e1);
370 * Returns the namespace of the given node name. If the node name is
371 * separated by colon, the it splits with colon and forms the namespace.
372 * If the node name is formed with underscore, then it splits the node
373 * name consecutively to figure out the proper module name.
375 * @param childName node name
376 * @param ctx schema context
377 * @param parent parent properties node
378 * @param curSchema current schema
379 * @return namespace of the given node
381 static Namespace getNamespace(String childName, SchemaContext ctx,
382 PropertiesNode parent, SchemaNode curSchema) {
384 Namespace parentNs = parent.namespace();
385 Namespace ns = new Namespace(parentNs.moduleName(),
386 parentNs.moduleNs(), parentNs.revision());
387 int lastIndexOfColon = childName.lastIndexOf(COLON);
388 if (lastIndexOfColon != -1) {
389 String moduleName = childName.substring(0, lastIndexOfColon);
390 childName = childName.substring(lastIndexOfColon+1);
391 Namespace ns1 = getNs(moduleName, ctx);
397 SchemaNode child = getChildSchemaNode(curSchema, childName, ns);
399 if (child == null && childName.contains(UNDERSCORE)) {
400 String[] children = childName.split(UNDERSCORE);
401 String second = childName.substring(children[0].length() + 1);
402 StringBuilder first = new StringBuilder();
404 for (int i =0; i< children.length; i++) {
405 String moduleName = first + children[i];
406 Namespace newNs = getNs(moduleName, ctx);
410 first.append(children[i]).append(UNDERSCORE);
411 if (i + 1 < children.length) {
412 second = second.replaceFirst(
413 children[i + 1] + UNDERSCORE, "");
422 * Returns the namespace by finding the given module in the schema context.
424 * @param modName module name
425 * @param ctx schema context
426 * @return namespace of the given node name
428 private static Namespace getNs(String modName, SchemaContext ctx) {
429 Iterator<Module> it = ctx.findModules(modName).iterator();
431 Module m = it.next();
432 return new Namespace(modName, m.getQNameModule().getNamespace(),
433 getRevision(m.getRevision()));
439 * Returns child schema node.
441 * @param curSchema current schema node
442 * @param name name of the property
443 * @param namespace namespace of the property
444 * @return child schema node
446 public static SchemaNode getChildSchemaNode(SchemaNode curSchema,
448 Namespace namespace) {
449 if (namespace == null) {
453 QName qname = QName.create(namespace.moduleNs(),
454 Revision.of(namespace.revision()), name);
456 // YANG RPC will not be instance of DataSchemaNode
457 if (curSchema instanceof DataSchemaNode) {
458 Deque<DataSchemaNode> schemaNodeDeque = ParserStreamUtils.
459 findSchemaNodeByNameAndNamespace(((DataSchemaNode)
460 curSchema), name, namespace.moduleNs());
461 if (schemaNodeDeque.isEmpty()) {
462 // could not find schema node
466 DataSchemaNode schemaNode = schemaNodeDeque.pop();
467 if (schemaNodeDeque.isEmpty()){
472 // node is child of Choice/case
473 return SchemaUtils.findSchemaForChild(((ChoiceSchemaNode) schemaNode),
476 return SchemaUtils.findDataChildSchemaByQName(curSchema, qname);
481 * Returns the property node type.
483 * @param index current index
484 * @param length length of the properties
485 * @param name name of the property
486 * @return the property node type
488 public static NodeType getNodeType(int index, int length, String name,
490 if (index == length-1) {
491 if (schema instanceof AnyXmlSchemaNode){
492 return NodeType.ANY_XML_NODE;
494 return (isListEntry(name) ? NodeType.MULTI_INSTANCE_LEAF_NODE :
495 NodeType.SINGLE_INSTANCE_LEAF_NODE);
497 return (isListEntry(name) ? NodeType.MULTI_INSTANCE_NODE :
498 NodeType.SINGLE_INSTANCE_NODE);
503 * Returns revision in string.
505 * @param r YANG revision
506 * @return revision in string
508 public static String getRevision(Optional<Revision> r) {
509 return (r.isPresent()) ? r.get().toString() : null;
513 * Returns value namespace for leaf value.
515 * @param value value of the leaf
516 * @param ctx schema context
517 * @return value namespace
518 * @throws SvcLogicException if identity/module could not be found
520 static Namespace getValueNamespace(String value,
522 throws SvcLogicException {
523 String prefix = getPrefixFromValue(value);
524 if (prefix == null) {
528 IdentitySchemaNode id = IdentityCodecUtil.parseIdentity(value,
531 final Iterator<Module> modules = ctx.findModules(prefix).iterator();
532 checkArgument(modules.hasNext(), "Could not find " +
533 "module %s", prefix);
534 return modules.next().getQNameModule();
538 throw new SvcLogicException("Could not find identity");
541 return getModuleNamespace(id.getQName(), ctx);
544 private static String getPrefixFromValue(String value) {
545 int lastIndexOfColon = value.lastIndexOf(":");
546 if (lastIndexOfColon != -1) {
547 return value.substring(0, lastIndexOfColon);
553 * Returns module namespace from a given qName.
555 * @param qName qName of a node
556 * @param ctx schema context
557 * @return module namespace of the node
558 * @throws SvcLogicException when the module is not available
560 public static Namespace getModuleNamespace(QName qName, SchemaContext ctx)
561 throws SvcLogicException {
562 Optional<Module> module = ctx.findModule(qName.getModule());
563 if (!module.isPresent()) {
564 throw new SvcLogicException("Could not find module node");
566 Module m = module.get();
567 return new Namespace(m.getName(), m.getQNameModule().getNamespace(),
568 getRevision(m.getRevision()));
571 static String getParsedValue(Namespace valNs, String value) {
572 if (valNs != null && value.contains(":")) {
573 String[] valArr = value.split(":");