[CONTROLLER-169] PUT toaster:toaster on toaster sample throwing exception, indicator of [de] serialization issue Created: 20/Feb/14  Updated: 25/Jul/23  Due: 22/Apr/14  Resolved: 21/May/14

Status: Resolved
Project: controller
Component/s: mdsal
Affects Version/s: None
Fix Version/s: None

Type: Bug
Reporter: David Bainbridge Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Operating System: Mac OS
Platform: Macintosh


Issue Links:
Duplicate
is duplicated by YANGTOOLS-101 YANG Enumeration type is not handled. Resolved
External issue ID: 442
Priority: Normal

 Description   

Attempting to to a

PUT /restconf/config/toaster:toaster/ HTTP/1.1
Host: admin:admin@localhost:8080
Content-Type: application/yang.data+json
Cache-Control: no-cache

{ "toaster:toaster" :

{ "toasterManufacturer" : "foo", "toasterModelNumber" : "1234567", "toasterStatus" : "up" }

}

returns 200 Ok, causes an exception in the log (below) and does not reflect any data change in the operational store.

2014-02-20 14:02:22.950 PST [pool-20-thread-3] ERROR o.o.y.s.b.g.i.LazyGeneratedCodecRegistry - Could not find loaded class for path: SchemaPath [path=[(http://netconfcentral.org/ns/toaster?revision=2009-11-20)toaster], absolute=true] and type: org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster
2014-02-20 14:02:22.954 PST [pool-20-thread-3] ERROR o.o.c.s.b.i.c.d.BindingIndependentConnector - Ommiting from BA transaction: /(http://netconfcentral.org/ns/toaster?revision=2009-11-20)toaster.
org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException: java.lang.NullPointerException
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.tryDeserialization(RuntimeGeneratedMappingServiceImpl.java:455) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.fromDataDom(RuntimeGeneratedMappingServiceImpl.java:437) ~[bundlefile:na]
at org.opendaylight.controller.config.yang.md.sal.binding.impl.RuntimeMappingModule$RuntimeGeneratedMappingServiceProxy.fromDataDom(RuntimeMappingModule.java:140) ~[bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector.createDomToBindingTransaction(BindingIndependentConnector.java:239) [bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector.access$900(BindingIndependentConnector.java:93) [bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector$DomToBindingCommitHandler.requestCommit(BindingIndependentConnector.java:504) [bundlefile:na]
at org.opendaylight.controller.md.sal.common.impl.service.TwoPhaseCommit.call(TwoPhaseCommit.java:90) [bundlefile:na]
at org.opendaylight.controller.md.sal.common.impl.service.TwoPhaseCommit.call(TwoPhaseCommit.java:38) [bundlefile:na]
at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_51]
at java.lang.Thread.run(Thread.java:744) [na:1.7.0_51]
Caused by: java.lang.NullPointerException: null
at org.opendaylight.yangtools.sal.binding.generator.impl.LazyGeneratedCodecRegistry.getClassForPath(LazyGeneratedCodecRegistry.java:190) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.InstanceIdentifierCodecImpl._deserializePathArgument(InstanceIdentifierCodecImpl.java:110) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.InstanceIdentifierCodecImpl.deserializePathArgument(InstanceIdentifierCodecImpl.java:271) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.InstanceIdentifierCodecImpl.deserialize(InstanceIdentifierCodecImpl.java:83) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$10.call(RuntimeGeneratedMappingServiceImpl.java:433) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$10.call(RuntimeGeneratedMappingServiceImpl.java:429) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.tryDeserialization(RuntimeGeneratedMappingServiceImpl.java:450) ~[bundlefile:na]
... 11 common frames omitted



 Comments   
Comment by Tony Tkacik [ 21/Feb/14 ]

Hi David,
deserialization exception is logged because no Binding Aware Component is actually listening or participating in that put operation, thus no codecs exist (since no-one needs that data).

The exception itself is bit confusing, so I would suggest improving error reporting, that no-one is actually listening to that data, rather then showing exception (this exception is correct state), but confuses people that something is broken inside MD-SAL.

Comment by David Bainbridge [ 21/Feb/14 ]

So presumably what is happening is that after the data is put into the config store, the SAL wants to send a notification to anyone listening that the config data has changed.

Either the SAL knows that no one has registered to listen, in which case it would not need to deserialize the data or the SAL is blind to the list of listeners and thus needs to deserialize the data an attempt to send an event that no one receives.

If the SAL knows no one is listening, then I would think no deserialization would ever take place, it could just issue an error / warning because some configuration data was pushed that will never be used.

If the SAL is not aware then I can see that it might attempt to deserialize the data depending on the code path, but I am not sure why that would cause an exception. Presumably the Java DTO objects can be found that represent the data and thus the data could be mashalled into those objects.

So I guess the question is, what is being deserialized that causes the failures? I haven't walked this with the debugger yet, as my assumption was this was related to the other bugs with serialization around the toaster example.

I agree a warning or error indicating no one is listening and the data is essentially unused is valid.

Comment by David Bainbridge [ 21/Feb/14 ]

So I added a data provider listener to the toaster example and attempted a put, now I am getting the below exception, so i still think there may a bug here.

2014-02-21 11:48:09.187 PST [pool-20-thread-4] ERROR o.o.c.s.b.i.c.d.BindingIndependentConnector - Ommiting from BA transaction: /(http://netconfcentral.org/ns/toaster?revision=2009-11-20)toaster.
org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException: java.lang.ClassCastException: java.lang.String cannot be cast to org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster$ToasterStatus
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.tryDeserialization(RuntimeGeneratedMappingServiceImpl.java:455) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.dataObjectFromDataDom(RuntimeGeneratedMappingServiceImpl.java:597) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.dataObjectFromDataDom(RuntimeGeneratedMappingServiceImpl.java:423) ~[bundlefile:na]
at org.opendaylight.controller.config.yang.md.sal.binding.impl.RuntimeMappingModule$RuntimeGeneratedMappingServiceProxy.dataObjectFromDataDom(RuntimeMappingModule.java:135) ~[bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector.createDomToBindingTransaction(BindingIndependentConnector.java:240) [bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector.access$900(BindingIndependentConnector.java:93) [bundlefile:na]
at org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector$DomToBindingCommitHandler.requestCommit(BindingIndependentConnector.java:504) [bundlefile:na]
at org.opendaylight.controller.md.sal.common.impl.service.TwoPhaseCommit.call(TwoPhaseCommit.java:90) [bundlefile:na]
at org.opendaylight.controller.md.sal.common.impl.service.TwoPhaseCommit.call(TwoPhaseCommit.java:38) [bundlefile:na]
at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_51]
at java.lang.Thread.run(Thread.java:744) [na:1.7.0_51]
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster$ToasterStatus
at org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster$Broker$Codec$DOM.fromDomStatic(Toaster$Broker$Codec$DOM.java) ~[na:na]
at org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster$Broker$Codec$DOM.deserialize(Toaster$Broker$Codec$DOM.java) ~[na:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.LazyGeneratedCodecRegistry$DataContainerCodecImpl.deserialize(LazyGeneratedCodecRegistry.java:545) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$11.call(RuntimeGeneratedMappingServiceImpl.java:588) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$11.call(RuntimeGeneratedMappingServiceImpl.java:580) ~[bundlefile:na]
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl.tryDeserialization(RuntimeGeneratedMappingServiceImpl.java:450) ~[bundlefile:na]
... 12 common frames omitted

Comment by Tony Tkacik [ 09/Apr/14 ]

Other ways to reproduce:

2014-03-13 15:12:35 PDT [org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/restconf].[JAXRSRestconf]] SEVERE org.apache.catalina.core.StandardWrapperValve invoke Servlet.service() for servlet [JAXRSRestconf] in context with path [/restconf] threw exception [java.util.concurrent.ExecutionException: java.lang.IllegalStateException:
If a YANG Model contains a leaf of type enumeration, like this:

leaf node-connector-type {
type enumeration {
enum "CTRL"

{ value 0; description "Represents the OFPP_CONTROLLER reserved port to forward a packet to the controller, this is to send data packets to the controller from the data plane triggering a packet_in event."; }

enum "ALL"

{ value 1; description "Represents the OFPP_ALL reserved OF port to forward to ALL the ports in the system , should be used for flooding like mechanism to be used cautiously to avoid excessive flooding."; }

And the value is passed in via RestConf as let's say "ALL", then YANGTools fails with the following ClassCastException.

org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException: java.lang.ClassCastException: java.lang.String cannot be cast to org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140305.host.NodeConnector$NodeConnectorType] with root cause
java.lang.ClassCastException: java.lang.String cannot be cast to org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140305.host.NodeConnector$NodeConnectorType
at org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140305.host.NodeConnector$Broker$Codec$DOM.fromDomStatic(NodeConnector$Broker$Codec$DOM.java)
at org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140305.AddStaticHostInput$Broker$Codec$DOM.fromDomStatic(AddStaticHostInput$Broker$Codec$DOM.java)
at org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140305.AddStaticHostInput$Broker$Codec$DOM.deserialize(AddStaticHostInput$Broker$Codec$DOM.java)
at org.opendaylight.yangtools.sal.binding.generator.impl.LazyGeneratedCodecRegistry$DataContainerCodecImpl.deserialize(LazyGeneratedCodecRegistry.java:629)
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$11.call(RuntimeGeneratedMappingServiceImpl.java:590)
at org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl$11.call(RuntimeGeneratedMappingServiceImpl.java:582

Comment by Tony Tkacik [ 21/May/14 ]

With new default datastore this does not happen.

Generated at Wed Feb 07 19:52:22 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.