[MDSAL-668]  Issue serializing object type defined by a leafref Created: 15/Jun/21  Updated: 16/Jun/21  Resolved: 16/Jun/21

Status: Resolved
Project: mdsal
Component/s: Binding runtime
Affects Version/s: None
Fix Version/s: 8.0.0, 7.0.8

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

Attachments: File model-test.tar.gz    
Issue Links:
Issue split
split to MDSAL-670 BindingCodecContext does not deal wit... In Progress
split to MDSAL-669 Retain grouping/uses instantiation ve... Resolved

 Description   

In TransportPCE, we have encountered an issue since Silicon with the implementation of org-openroadm-device@2020-05-29.yang model.
The problem is located in line 1300:

leaf-list port-list {
  type leafref {
    path "/org-openroadm-device/circuit-packs[circuit-pack-name=current()/../circuit-pack-name]/ports/port-name";
  }

  description "port list";
  }
}

 

The List<?> type of port-list, generated during compilation of the model, seems not being taken into account during serialization step and throws an IllegalStateException:

Caused by: java.lang.IllegalStateException: Unexpected return type ?
	at org.opendaylight.mdsal.binding.dom.codec.impl.BindingCodecContext.getLeafNodesUsingReflection(BindingCodecContext.java:386) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.BindingCodecContext.getLeafNodes(BindingCodecContext.java:355) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.<init>(DataObjectCodecContext.java:102) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.ListNodeCodecContext.<init>(ListNodeCodecContext.java:28) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.KeyedListNodeCodecContext.<init>(KeyedListNodeCodecContext.java:54) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.KeyedListNodeCodecContext$Unordered.<init>(KeyedListNodeCodecContext.java:41) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.KeyedListNodeCodecContext.create(KeyedListNodeCodecContext.java:71) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataContainerCodecPrototype.createInstance(DataContainerCodecPrototype.java:237) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataContainerCodecPrototype.loadInstance(DataContainerCodecPrototype.java:224) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataContainerCodecPrototype.get(DataContainerCodecPrototype.java:220) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.streamChild(DataObjectCodecContext.java:195) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.CodecDataObject.codecMember(CodecDataObject.java:81) ~[?:?]
	at org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev200529.circuit.pack.Ports$$$codecImpl.getSupportingPortList(Unknown Source) ~[?:?]
	at org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev200529.circuit.pack.Ports$$$streamer.serialize(Unknown Source) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectStreamer.commonStreamList(DataObjectStreamer.java:153) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectStreamer.streamMap(DataObjectStreamer.java:133) ~[?:?]
	at org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev200529.circuit.packs.CircuitPacks$$$streamer.serialize(Unknown Source) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.BindingCodecContext$DataObjectSerializerProxy.serialize(BindingCodecContext.java:121) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.impl.BindingCodecContext.toNormalizedNode(BindingCodecContext.java:506) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.spi.ForwardingBindingDOMCodecServices.toNormalizedNode(ForwardingBindingDOMCodecServices.java:66) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.codec.spi.ForwardingBindingDOMCodecServices.toNormalizedNode(ForwardingBindingDOMCodecServices.java:66) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.adapter.BindingDOMWriteTransactionAdapter.toNormalized(BindingDOMWriteTransactionAdapter.java:107) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.adapter.BindingDOMWriteTransactionAdapter.toNormalized(BindingDOMWriteTransactionAdapter.java:100) ~[?:?]
	at org.opendaylight.mdsal.binding.dom.adapter.BindingDOMWriteTransactionAdapter.merge(BindingDOMWriteTransactionAdapter.java:50) ~[?:?]
	at org.opendaylight.transportpce.common.device.DeviceTransaction.merge(DeviceTransaction.java:66) ~[?:?]
	at org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl710.postEquipmentState(OpenRoadmInterfacesImpl710.java:225) ~[?:?]
	at org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl.postEquipmentState(OpenRoadmInterfacesImpl.java:127) ~[?:?]


 Comments   
Comment by Robert Varga [ 15/Jun/21 ]

The ISE is caused by our inability to deal with WildcardType, from whence we should be taking the upper bound – but that will typically not exist, so we'd circle to Object.class and defer to NOOP codec – which is what we have historically done.

While that would happen to work for the concrete case at hand, it is the incorrect thing to do in general.

The List could contain InstanceIdentifier (which needs to be translated to YangInstanceIdentifiers), j.l.Class (which needs to be translated to QNames), or various generated TypeObject subclasses (which need to be decapsulated/translated).

At the end of the day, the current approach to codec lookup is inadequate, as the codec link cannot always be accurately ascertained by pure reflection. This, by the way, also affect leaf nodes, but is hidden by the fact we return an Object and (again) default to NOOP codec.

Comment by Robert Varga [ 15/Jun/21 ]

This case can only happen when the leafref target cannot be resolved, which means the binding construct is somewhere inside a grouping and therefore we are (again) dealing with an ambiguity coming from not operating on instantiated context – i.e. the construct at hand could end up being interpreted as List<InstanceIdentifier> or List<String> in two different instantiations of the grouping where it is defined.

There are multiple difficulties here:

  1. establishing instantiation cardinality of the grouping at hand. There can be 0, 1, or more instantiations. For 0 instantiations we should not be hitting this case anyway and we should never be calling on this codec (because there is no NormalizedNode manifestation). For one instantiation, we can use type information from that instantiation and inline it in the grouping scope – and use a static codec just as we do in other cases.
  2. for multiple instantiations we need to determine what the possible typing instantiation is. If we can prove it is always the same type, we can again hoist as in the case of a single instantiation. For multiple resulting types we need to have polymorphic codec, which is somehow specialized for each possible instantiation.
  3. we also need to deal with the first two in a scalable manner, which hopefully does not force us outside of our well-trodded lazy initialization mode of operation. That probably requires communicating (on-demand?) instantiation information along the $$$streamer/$$$codecImpl chain.

The good news is that if we can determine cardinatility to be 1, we can also use the currently-unused CodecDataObjectGenerator.Fixed, which offers runtime performance benefits, as noted in MDSAL-443.

Comment by Robert Varga [ 16/Jun/21 ]

So the ISE is in scope of this issue. Correction of codec lookup is part of MDSAL-670, which will be done separately.

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