[NETCONF-563] NetconfMessageTransformUtil.toFilterStructure() fails for leaf instance identifiers Created: 24/Aug/18  Updated: 08/Dec/21  Resolved: 04/Sep/18

Status: Resolved
Project: netconf
Component/s: netconf
Affects Version/s: Oxygen, Fluorine
Fix Version/s: Neon, Oxygen SR4, Fluorine SR1

Type: Bug Priority: High
Reporter: Robert Varga Assignee: Robert Varga
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Relates
relates to YANGTOOLS-898 Rework ImmutableNodes.fromInstanceId() Resolved
relates to NETCONF-833 Leaf Node cannot be deleted inside NE... Resolved

 Description   

This utility method is used by NETCONF plugin to create a filter expression and write it out. Unfortunately this functionality relied leaf nodes having a null value, which would in turn be recognized and ignored by codecs.

Null-valued leaves are no longer available, which breaks the ability to create filters for simple leaves, rendering sal-netconf-connector inoperable for requests to read individual leaves.



 Comments   
Comment by Robert Varga [ 24/Aug/18 ]

Stack trace of evidence:

java.lang.IllegalStateException: Value has not been set
    at com.google.common.base.Preconditions.checkState(Preconditions.java:504) [81:com.google.guava:23.6.1.jre]
    at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.AbstractImmutableNormalizedNodeBuilder.getValue(AbstractImmutableNormalizedNodeBuilder.java:33) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder.build(ImmutableLeafNodeBuilder.java:27) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder.build(ImmutableLeafNodeBuilder.java:17) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToSimpleNodes.create(InstanceIdToSimpleNodes.java:50) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:105) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:105) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:105) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:105) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:105) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.fromInstanceId(ImmutableNodes.java:147) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.fromInstanceId(ImmutableNodes.java:110) [323:org.opendaylight.yangtools.yang-data-impl:2.0.6.1]
    at org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure(NetconfMessageTransformUtil.java:187) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.util.NetconfRpcStructureTransformer.toFilterStructure(NetconfRpcStructureTransformer.java:46) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps.getConfig(NetconfBaseOps.java:185) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps.getConfigRunning(NetconfBaseOps.java:223) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps.getConfigRunningData(NetconfBaseOps.java:199) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.sal.tx.ReadOnlyTx.readConfigurationData(ReadOnlyTx.java:43) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
    at org.opendaylight.netconf.sal.connect.netconf.sal.tx.ReadOnlyTx.read(ReadOnlyTx.java:67) [301:org.opendaylight.netconf.sal-netconf-connector:1.7.3]
Comment by Robert Varga [ 24/Aug/18 ]

One way of fixing this would be to store Empty instance in the leaf, but that would only paper over the problem, leading to a failure to serialize the data, as both JSON and XML codecs rely on schema information to select the correct codec – leading to ClassCastException when the leaf's value is accessed for serialization.

Another way would be to select an 'empty' value, which could work except numeric types do not have such a value – leading to a partially-working solution.

Comment by Robert Varga [ 24/Aug/18 ]

This is an extreme edge case, which should be handled in NETCONF. toFilterStructure() is returning an anyxml node, for which it really needs only an Element with proper structure to use in DOMSource. Current code does this rather inefficiently by creating a NormalizedNode from YangInstanceIdentifier and then instantiating XML codec pipeline to encode that into the target Element.

Skipping the NormalizedNode/codec steps will remove the edge case and also improve the performance of this method.

Comment by Robert Varga [ 24/Aug/18 ]

The code looks like this, making it clear there is block we can replace:

        final Element element = XmlUtil.createElement(BLANK_DOCUMENT, NETCONF_FILTER_QNAME.getLocalName(),
                Optional.of(NETCONF_FILTER_QNAME.getNamespace().toString()));
        element.setAttributeNS(NETCONF_FILTER_QNAME.getNamespace().toString(), NETCONF_TYPE_QNAME.getLocalName(),
                "subtree");

        try {
            NetconfUtil.writeNormalizedNode(ImmutableNodes.fromInstanceId(ctx, identifier), new DOMResult(element),
                SchemaPath.ROOT, ctx);
        } catch (IOException | XMLStreamException e) {
            throw new IllegalStateException("Unable to serialize filter element for path " + identifier, e);
        }
        anyXmlBuilder.withValue(new DOMSource(element));
Comment by Robert Varga [ 26/Aug/18 ]

So here we need the XML serializer to deal with leaf values (in case of NodeIdentifierWithPredicates), but for that we certainly do not need a NormalizedNode representation of the YangInstanceIdentifier. Hence NetconfUtil should grow a writeYangInstanceIdentifier(), which will instantiate the XML codec (to deal with values) and drive it using NormalizedNodeStreamWriter interface based on the content of YangInstanceIdentifier.

Generated at Wed Feb 07 20:15:20 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.