From 5e2a4e8e11594b5cb49c6e73dd3b2d724b038135 Mon Sep 17 00:00:00 2001 From: Jan Hajnar Date: Tue, 21 Apr 2015 19:11:52 +0200 Subject: [PATCH] Bug 3024 - Restconf PUT exception when top level node is from augmentation * added check for PUT into JsonNormalizedNodeBodyReader. If method is PUT then data are unwraped from augmentations/choice nodes * added wrapping of augmentation nodes when using XmlNormalizedNodeBodyReader * commented out check for namespace in createConfigurationData (it should be moved to parse stage) * both XmlNormalizedNodeBodyReader and JsonNormalizedNodeBodyReader should now produce the same normalized node data and paths for equivalent XML and JSON input. Change-Id: I21f4594d20170f33177cbae00791b81f6ae640b2 Signed-off-by: Jan Hajnar --- .../impl/JsonNormalizedNodeBodyReader.java | 16 ++++++++-- .../impl/XmlNormalizedNodeBodyReader.java | 30 +++++++++++++++---- .../sal/restconf/impl/RestconfImpl.java | 13 ++++---- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java index e11cac2eb3..10399ffeff 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java @@ -27,6 +27,9 @@ import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; @@ -84,9 +87,18 @@ public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPr final JsonReader reader = new JsonReader(new InputStreamReader(entityStream)); jsonParser.parse(reader); - final NormalizedNode partialResult = resultHolder.getResult(); + NormalizedNode partialResult = resultHolder.getResult(); final NormalizedNode result; - if(partialResult instanceof MapNode) { + + // unwrap result from augmentation and choice nodes on PUT + if (!isPost()) { + while (partialResult instanceof AugmentationNode || partialResult instanceof ChoiceNode) { + final Object childNode = ((DataContainerNode) partialResult).getValue().iterator().next(); + partialResult = (NormalizedNode) childNode; + } + } + + if (partialResult instanceof MapNode) { result = Iterables.getOnlyElement(((MapNode) partialResult).getValue()); } else { result = partialResult; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java index 4257e172b4..74a9bd2d31 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java @@ -34,6 +34,8 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils; import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; @@ -126,18 +128,25 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro final String docRootElm = doc.getDocumentElement().getLocalName(); final String schemaNodeName = pathContext.getSchemaNode().getQName().getLocalName(); + // FIXME the factory instance should be cached if the schema context is the same + final DomToNormalizedNodeParserFactory parserFactory = + DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, pathContext.getSchemaContext()); + if (!schemaNodeName.equalsIgnoreCase(docRootElm)) { final DataSchemaNode foundSchemaNode = findSchemaNodeOrParentChoiceByName(schemaNode, docRootElm); if (foundSchemaNode != null) { + if (schemaNode instanceof AugmentationTarget) { + final AugmentationSchema augmentSchemaNode = findCorrespondingAugment(schemaNode, foundSchemaNode); + if (augmentSchemaNode != null) { + return parserFactory.getAugmentationNodeParser().parse(elements, augmentSchemaNode); + } + } schemaNode = foundSchemaNode; } } - // FIXME the factory instance should be cached if the schema context is the same - final DomToNormalizedNodeParserFactory parserFactory = - DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, pathContext.getSchemaContext()); - NormalizedNode parsed = null; + if(schemaNode instanceof ContainerSchemaNode) { return parserFactory.getContainerNodeParser().parse(Collections.singletonList(doc.getDocumentElement()), (ContainerSchemaNode) schemaNode); } else if(schemaNode instanceof ListSchemaNode) { @@ -147,7 +156,6 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro final ChoiceSchemaNode casted = (ChoiceSchemaNode) schemaNode; return parserFactory.getChoiceNodeParser().parse(elements, casted); } - // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode return parsed; @@ -175,5 +183,17 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro } return null; } + + private static AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) { + if (parent instanceof AugmentationTarget && !((parent instanceof ChoiceCaseNode) || (parent instanceof ChoiceSchemaNode))) { + for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) { + DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName()); + if (childInAugmentation != null) { + return augmentation; + } + } + } + return null; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java index 33795889a1..8e88be6f50 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java @@ -828,12 +828,13 @@ public class RestconfImpl implements RestconfService { throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); } - final URI payloadNS = payload.getData().getNodeType().getNamespace(); - if (payloadNS == null) { - throw new RestconfDocumentedException( - "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)", - ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE); - } + // FIXME: move this to parsing stage (we can have augmentation nodes here which do not have namespace) +// final URI payloadNS = payload.getData().getNodeType().getNamespace(); +// if (payloadNS == null) { +// throw new RestconfDocumentedException( +// "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)", +// ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE); +// } final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint(); final InstanceIdentifierContext iiWithData = payload.getInstanceIdentifierContext(); -- 2.36.6