diff options
author | ToineSiebelink <toine.siebelink@est.tech> | 2020-11-10 16:32:50 +0000 |
---|---|---|
committer | Ruslan Kashapov <ruslan.kashapov@pantheon.tech> | 2020-12-01 13:24:01 +0200 |
commit | 46a7718bc0f0d2951ed18795c85f6961f839df25 (patch) | |
tree | f1d521a52247897e22718fa71b7c61bdfce3d1f1 | |
parent | e731118eca0540792a140803f18c298fb3be132d (diff) |
Xpath builder on data fragmentation
Issue-ID: CPS-72
Change-Id: Iab5be2bf0dd7d5540b8880bbf5ab2c6ed9342a9e
Signed-off-by: Ruslan Kashapov <ruslan.kashapov@pantheon.tech>
3 files changed, 54 insertions, 12 deletions
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/Fragment.java b/cps-service/src/main/java/org/onap/cps/api/impl/Fragment.java index 252b09e5cd..90c92f905e 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/Fragment.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/Fragment.java @@ -39,7 +39,7 @@ import org.opendaylight.yangtools.yang.model.api.Module; public class Fragment { @Getter - private String xpath; + private final String xpath; @Getter private final Map<String, Object> attributes = new HashMap<>(); @@ -62,9 +62,10 @@ public class Fragment { * * @param module the Yang module that encompasses this fragment * @param qnames the list of qualified names that points the schema node for this fragment + * @param xpath the xpath of root fragment */ - public static Fragment createRootFragment(final Module module, final QName... qnames) { - return new Fragment(null, module, qnames); + public static Fragment createRootFragment(final Module module, final QName[] qnames, final String xpath) { + return new Fragment(null, module, qnames, xpath); } /** @@ -72,24 +73,27 @@ public class Fragment { * * @param parentFragment the parent (can be null for 'root' objects) * @param module the Yang module that encompasses this fragment - * @param qnames the list of qualified names that points the schema node for this fragment + * @param qnames array of qualified names that points the schema node for this fragment + * @param xpath the xpath for this fragment */ - private Fragment(final Fragment parentFragment, final Module module, final QName... qnames) { + private Fragment(final Fragment parentFragment, final Module module, final QName[] qnames, String xpath) { this.parentFragment = parentFragment; this.module = module; this.qnames = qnames; + this.xpath = xpath; } /** * Create a Child Fragment where the current Fragment is the parent. * - * @param qnameChild The Qualified name for the child (relative to the parent) + * @param childQname The Qualified name for the child (relative to the parent) + * @param childXPath The child xpath (relative to the parrent) * @return the child fragment */ - public Fragment createChildFragment(final QName qnameChild) { + public Fragment createChildFragment(final QName childQname, final String childXPath) { final QName[] qnamesForChild = Arrays.copyOf(qnames, qnames.length + 1); - qnamesForChild[qnamesForChild.length - 1] = qnameChild; - final Fragment childFragment = new Fragment(this, module, qnamesForChild); + qnamesForChild[qnamesForChild.length - 1] = childQname; + final Fragment childFragment = new Fragment(this, module, qnamesForChild, getXpath() + childXPath); childFragments.add(childFragment); return childFragment; } diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java b/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java index 0f05d7d923..071ff6ad3b 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java +++ b/cps-service/src/main/java/org/onap/cps/utils/YangUtils.java @@ -24,12 +24,16 @@ import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.ServiceLoader; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.onap.cps.api.impl.Fragment; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; @@ -116,8 +120,9 @@ public class YangUtils { public static Fragment fragmentNormalizedNode( final NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?> tree, final Module module) { - final QName nodeType = tree.getNodeType(); - final Fragment rootFragment = Fragment.createRootFragment(module, nodeType); + final QName[] nodeTypes = {tree.getNodeType()}; + final String xpath = buildXpathId(tree.getIdentifier()); + final Fragment rootFragment = Fragment.createRootFragment(module, nodeTypes, xpath); fragmentNormalizedNode(rootFragment, tree); return rootFragment; } @@ -167,8 +172,37 @@ public class YangUtils { private static void createNodeForEachListElement(final Fragment currentFragment, final MapNode mapNode) { final Collection<MapEntryNode> mapEntryNodes = mapNode.getValue(); for (final MapEntryNode mapEntryNode : mapEntryNodes) { - final Fragment listElementFragment = currentFragment.createChildFragment(mapNode.getNodeType()); + final String xpathId = buildXpathId(mapEntryNode.getIdentifier()); + final Fragment listElementFragment = + currentFragment.createChildFragment(mapNode.getNodeType(), xpathId); fragmentNormalizedNode(listElementFragment, mapEntryNode); } } + + private static String buildXpathId(final YangInstanceIdentifier.PathArgument nodeIdentifier) { + final StringBuilder xpathIdBuilder = new StringBuilder(); + xpathIdBuilder.append("/").append(nodeIdentifier.getNodeType().getLocalName()); + + if (nodeIdentifier instanceof NodeIdentifierWithPredicates) { + xpathIdBuilder.append(getKeyAttributesStatement((NodeIdentifierWithPredicates) nodeIdentifier)); + } + return xpathIdBuilder.toString(); + } + + private static String getKeyAttributesStatement(final NodeIdentifierWithPredicates nodeIdentifier) { + final List<String> keyAttributes = nodeIdentifier.entrySet().stream().map( + entry -> { + final String name = entry.getKey().getLocalName(); + final String value = String.valueOf(entry.getValue()).replace("'", "\\'"); + return String.format("@%s='%s'", name, value); + } + ).collect(Collectors.toList()); + + if (keyAttributes.isEmpty()) { + return ""; + } else { + Collections.sort(keyAttributes); + return "[" + String.join(" and ", keyAttributes) + "]"; + } + } } diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/YangUtilsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/YangUtilsSpec.groovy index 6a463ad6f5..801e43079a 100644 --- a/cps-service/src/test/groovy/org/onap/cps/utils/YangUtilsSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/YangUtilsSpec.groovy @@ -96,6 +96,10 @@ class YangUtilsSpec extends Specification{ result.childFragments.size() == 2 and: 'each child (category) has the root fragment (result) as parent and in turn as 1 child (a list of books)' result.childFragments.each { it.parentFragment == result && it.childFragments.size() == 1 } + and: 'the fragments have the correct xpaths' + assert result.xpath == '/bookstore' + assert result.childFragments.collect { it.xpath } + .containsAll(["/bookstore/categories[@code='01']", "/bookstore/categories[@code='02']"]) } } |