From 6a1f273b365b774790585796f406490930bc7303 Mon Sep 17 00:00:00 2001 From: Jan Hajnar Date: Mon, 4 May 2015 16:57:49 +0200 Subject: [PATCH] Bug 3104 - Sal Rest Connector: Data already exists for path when adding new item to list in augmentation * changed XmlNormalizedNodeBodyReader and JsonNormalizedNodeBodyReader to return YangInstanceIdentifier pointing to root of payload data. * changed BrokerFacade datastore functions for PUT and POST to use returned path from reader without modifications * modified rest connector tests according to new behavior and added tests for POST when payload is from augment/choice Change-Id: Iac6a9853ea4c4529d2f484c464bd27123f4fafa2 Signed-off-by: Jan Hajnar (cherry picked from commit 3d4dc18c01ebca47030284dde81988a44424d821) --- .../impl/JsonNormalizedNodeBodyReader.java | 42 +++-- .../impl/XmlNormalizedNodeBodyReader.java | 78 ++++++---- .../sal/restconf/impl/BrokerFacade.java | 16 +- .../test/providers/TestJsonBodyReader.java | 128 ++++++++++------ .../test/providers/TestXmlBodyReader.java | 143 ++++++++++-------- .../restconf/impl/test/BrokerFacadeTest.java | 2 +- .../json/json_augment_choice_container.json | 5 + .../json/json_augment_container.json | 5 + .../xml/xml_augment_choice_container.xml | 3 + .../xml/xml_augment_container.xml | 3 + .../yang/augment-module.yang | 56 ++++++- 11 files changed, 312 insertions(+), 169 deletions(-) create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_choice_container.json create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_container.json create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_container.xml 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 5d63c9c011..bacd38720c 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 @@ -14,6 +14,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; @@ -27,9 +29,11 @@ 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.YangInstanceIdentifier; 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.MapEntryNode; 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; @@ -88,23 +92,35 @@ public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPr final JsonReader reader = new JsonReader(new InputStreamReader(entityStream)); jsonParser.parse(reader); - NormalizedNode partialResult = resultHolder.getResult(); - final NormalizedNode result; + NormalizedNode result = resultHolder.getResult(); + List iiToDataList = new ArrayList<>(); + InstanceIdentifierContext newIIContext; - // FIXME: Also II should be updated 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 (isPost()) { + while (result instanceof AugmentationNode || result instanceof ChoiceNode) { + final Object childNode = ((DataContainerNode) result).getValue().iterator().next(); + iiToDataList.add(result.getIdentifier()); + result = (NormalizedNode) childNode; + } + if (result instanceof MapEntryNode) { + iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(result.getNodeType())); + iiToDataList.add(result.getIdentifier()); + } else { + iiToDataList.add(result.getIdentifier()); } - } - - if (partialResult instanceof MapNode && !isPost()) { - result = Iterables.getOnlyElement(((MapNode) partialResult).getValue()); } else { - result = partialResult; + if (result instanceof MapNode) { + result = Iterables.getOnlyElement(((MapNode) result).getValue()); + } } - return new NormalizedNodeContext(path,result); + + YangInstanceIdentifier fullIIToData = YangInstanceIdentifier.create(Iterables.concat( + path.getInstanceIdentifier().getPathArguments(), iiToDataList)); + + newIIContext = new InstanceIdentifierContext<>(fullIIToData, path.getSchemaNode(), path.getMountPoint(), + path.getSchemaContext()); + + return new NormalizedNodeContext(newIIContext, result); } catch (final RestconfDocumentedException e) { throw e; } catch (final ResultAlreadySetException e) { 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 2a9c5bf190..84cd660518 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 @@ -7,13 +7,16 @@ */ package org.opendaylight.controller.sal.rest.impl; +import com.google.common.collect.Iterables; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.WebApplicationException; @@ -31,8 +34,10 @@ 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.YangInstanceIdentifier; 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.SchemaUtils; 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; @@ -102,8 +107,7 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro } final Document doc = dBuilder.parse(entityStream); - final NormalizedNode result = parse(path,doc); - return new NormalizedNodeContext(path,result); + return parse(path,doc); } catch (final RestconfDocumentedException e){ throw e; } catch (final Exception e) { @@ -114,7 +118,7 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro } } - private static NormalizedNode parse(final InstanceIdentifierContext pathContext,final Document doc) { + private NormalizedNodeContext parse(final InstanceIdentifierContext pathContext,final Document doc) { final List elements = Collections.singletonList(doc.getDocumentElement()); final SchemaNode schemaNodeContext = pathContext.getSchemaNode(); @@ -128,66 +132,86 @@ public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPro } final String docRootElm = doc.getDocumentElement().getLocalName(); - final String schemaNodeName = pathContext.getSchemaNode().getQName().getLocalName(); + List iiToDataList = new ArrayList<>(); + InstanceIdentifierContext outIIContext; + // 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); - } + if (isPost()) { + final Deque foundSchemaNodes = findPathToSchemaNodeByName(schemaNode, docRootElm); + while (!foundSchemaNodes.isEmpty()) { + Object child = foundSchemaNodes.pop(); + if (child instanceof AugmentationSchema) { + final AugmentationSchema augmentSchemaNode = (AugmentationSchema) child; + iiToDataList.add(SchemaUtils.getNodeIdentifierForAugmentation(augmentSchemaNode)); + } else if (child instanceof DataSchemaNode) { + schemaNode = (DataSchemaNode) child; + iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(schemaNode.getQName())); } - schemaNode = foundSchemaNode; } } + YangInstanceIdentifier fullIIToData = YangInstanceIdentifier.create(Iterables.concat( + pathContext.getInstanceIdentifier().getPathArguments(), iiToDataList)); + + outIIContext = new InstanceIdentifierContext<>(fullIIToData, pathContext.getSchemaNode(), pathContext.getMountPoint(), + pathContext.getSchemaContext()); + NormalizedNode parsed = null; if(schemaNode instanceof ContainerSchemaNode) { - return parserFactory.getContainerNodeParser().parse(Collections.singletonList(doc.getDocumentElement()), (ContainerSchemaNode) schemaNode); + parsed = parserFactory.getContainerNodeParser().parse(Collections.singletonList(doc.getDocumentElement()), (ContainerSchemaNode) schemaNode); } else if(schemaNode instanceof ListSchemaNode) { final ListSchemaNode casted = (ListSchemaNode) schemaNode; - return parserFactory.getMapEntryNodeParser().parse(elements, casted); - } else if (schemaNode instanceof ChoiceSchemaNode) { - final ChoiceSchemaNode casted = (ChoiceSchemaNode) schemaNode; - return parserFactory.getChoiceNodeParser().parse(elements, casted); + parsed = parserFactory.getMapEntryNodeParser().parse(elements, casted); } // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode - return parsed; + return new NormalizedNodeContext(outIIContext, parsed); } - private static DataSchemaNode findSchemaNodeOrParentChoiceByName(DataSchemaNode schemaNode, String elementName) { + private static Deque findPathToSchemaNodeByName(DataSchemaNode schemaNode, String elementName) { + final Deque result = new ArrayDeque<>(); final ArrayList choiceSchemaNodes = new ArrayList<>(); final Collection children = ((DataNodeContainer) schemaNode).getChildNodes(); for (final DataSchemaNode child : children) { if (child instanceof ChoiceSchemaNode) { choiceSchemaNodes.add((ChoiceSchemaNode) child); } else if (child.getQName().getLocalName().equalsIgnoreCase(elementName)) { - return child; + result.push(child); + if (child.isAugmenting()) { + final AugmentationSchema augment = findCorrespondingAugment(schemaNode, child); + if (augment != null) { + result.push(augment); + } + } + return result; } } for (final ChoiceSchemaNode choiceNode : choiceSchemaNodes) { for (final ChoiceCaseNode caseNode : choiceNode.getCases()) { - final DataSchemaNode resultFromRecursion = findSchemaNodeOrParentChoiceByName(caseNode, elementName); - if (resultFromRecursion != null) { - // this returns top choice node in which child element is found - return choiceNode; + final Deque resultFromRecursion = findPathToSchemaNodeByName(caseNode, elementName); + if (!resultFromRecursion.isEmpty()) { + resultFromRecursion.push(choiceNode); + if (choiceNode.isAugmenting()) { + final AugmentationSchema augment = findCorrespondingAugment(schemaNode, choiceNode); + if (augment != null) { + resultFromRecursion.push(augment); + } + } + return resultFromRecursion; } } } - return null; + return result; } private static AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) { - if (parent instanceof AugmentationTarget && !((parent instanceof ChoiceCaseNode) || (parent instanceof ChoiceSchemaNode))) { + if (parent instanceof AugmentationTarget && !(parent instanceof ChoiceSchemaNode)) { for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) { DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName()); if (childInAugmentation != null) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java index 6a3adcccd6..24e1970ada 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.sal.restconf.impl; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; @@ -202,26 +201,19 @@ public class BrokerFacade { private CheckedFuture postDataViaTransaction( final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore, - final YangInstanceIdentifier parentPath, final NormalizedNode payload, final SchemaContext schemaContext) { + final YangInstanceIdentifier path, final NormalizedNode payload, final SchemaContext schemaContext) { // FIXME: This is doing correct post for container and list children // not sure if this will work for choice case if(payload instanceof MapNode) { - final YangInstanceIdentifier mapPath = parentPath.node(payload.getIdentifier()); - final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, mapPath); + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path); rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); - ensureParentsByMerge(datastore, mapPath, rWTransaction, schemaContext); + ensureParentsByMerge(datastore, path, rWTransaction, schemaContext); for(final MapEntryNode child : ((MapNode) payload).getValue()) { - final YangInstanceIdentifier childPath = mapPath.node(child.getIdentifier()); + final YangInstanceIdentifier childPath = path.node(child.getIdentifier()); checkItemDoesNotExists(rWTransaction, datastore, childPath); rWTransaction.put(datastore, childPath, child); } } else { - final YangInstanceIdentifier path; - if(payload instanceof MapEntryNode) { - path = parentPath.node(payload.getNodeType()).node(payload.getIdentifier()); - } else { - path = parentPath.node(payload.getIdentifier()); - } checkItemDoesNotExists(rWTransaction,datastore, path); ensureParentsByMerge(datastore, path, rWTransaction, schemaContext); rWTransaction.put(datastore, path, payload); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java index 36ce29b893..c1f463309b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java @@ -8,13 +8,14 @@ package org.opendaylight.controller.sal.rest.impl.test.providers; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; - +import com.google.common.base.Optional; +import com.google.common.collect.Sets; import java.io.InputStream; - +import java.net.URI; import javax.ws.rs.core.MediaType; - import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.JsonNormalizedNodeBodyReader; @@ -27,25 +28,25 @@ import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import com.google.common.base.Optional; - /** - * sal-rest-connector org.opendaylight.controller.sal.rest.impl.test.providers + * sal-rest-connector + * org.opendaylight.controller.sal.rest.impl.test.providers * * * * @author Vaclav Demcak * - * Created: Mar 11, 2015 + * Created: Mar 11, 2015 */ public class TestJsonBodyReader extends AbstractBodyReaderTest { private final JsonNormalizedNodeBodyReader jsonBodyReader; private static SchemaContext schemaContext; - public TestJsonBodyReader() throws NoSuchFieldException, SecurityException { + public TestJsonBodyReader () throws NoSuchFieldException, SecurityException { super(); jsonBodyReader = new JsonNormalizedNodeBodyReader(); } @@ -56,10 +57,8 @@ public class TestJsonBodyReader extends AbstractBodyReaderTest { } @BeforeClass - public static void initialization() throws NoSuchFieldException, - SecurityException { - schemaContext = schemaContextLoader("/instanceidentifier/yang", - schemaContext); + public static void initialization() throws NoSuchFieldException, SecurityException { + schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext); schemaContext = schemaContextLoader("/modules", schemaContext); schemaContext = schemaContextLoader("/invoke-rpc", schemaContext); controllerContext.setSchemas(schemaContext); @@ -67,45 +66,91 @@ public class TestJsonBodyReader extends AbstractBodyReaderTest { @Test public void moduleDataTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()); final String uri = "instance-identifier-module:cont"; mockBodyReader(uri, jsonBodyReader, false); final InputStream inputStream = TestJsonBodyReader.class .getResourceAsStream("/instanceidentifier/json/jsondata.json"); - final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = jsonBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); } @Test public void moduleSubContainerDataPutTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName); + final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName); final String uri = "instance-identifier-module:cont/cont1"; mockBodyReader(uri, jsonBodyReader, false); final InputStream inputStream = TestJsonBodyReader.class .getResourceAsStream("/instanceidentifier/json/json_sub_container.json"); - final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = jsonBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, - "cont1"); + checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII); } @Test public void moduleSubContainerDataPostTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName); final String uri = "instance-identifier-module:cont"; mockBodyReader(uri, jsonBodyReader, true); final InputStream inputStream = TestJsonBodyReader.class .getResourceAsStream("/instanceidentifier/json/json_sub_container.json"); - final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = jsonBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); + checkNormalizedNodeContext(returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); + } + + @Test + public void moduleSubContainerAugmentDataPostTest() throws Exception { + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next(); + QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment"); + YangInstanceIdentifier.AugmentationIdentifier augII = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(contAugmentQName)); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()) + .node(augII).node(contAugmentQName); + final String uri = "instance-identifier-module:cont"; + mockBodyReader(uri, jsonBodyReader, true); + final InputStream inputStream = TestXmlBodyReader.class + .getResourceAsStream("/instanceidentifier/json/json_augment_container.json"); + final NormalizedNodeContext returnValue = jsonBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); + } + + //FIXME: Uncomment this when JsonParserStream works correctly with case augmentation with choice + //@Test + public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception { + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next(); + QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1"); + QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2"); + final QName containerQName = QName.create(augmentChoice1QName, "case-choice-case-container1"); + YangInstanceIdentifier.AugmentationIdentifier augChoice1II = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(augmentChoice1QName)); + YangInstanceIdentifier.AugmentationIdentifier augChoice2II = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(augmentChoice2QName)); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()) + .node(augChoice1II).node(augmentChoice1QName).node(augChoice2II).node(augmentChoice2QName) + .node(containerQName); + final String uri = "instance-identifier-module:cont"; + mockBodyReader(uri, jsonBodyReader, true); + final InputStream inputStream = TestXmlBodyReader.class + .getResourceAsStream("/instanceidentifier/json/json_augment_choice_container.json"); + final NormalizedNodeContext returnValue = jsonBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); + checkNormalizedNodeContext(returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); } @Test @@ -139,26 +184,11 @@ public class TestJsonBodyReader extends AbstractBodyReaderTest { checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null); } - private void checkExpectValueNormalizeNodeContext( - final DataSchemaNode dataSchemaNode, - final NormalizedNodeContext nnContext, final String localQname) { - YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier - .of(dataSchemaNode.getQName()); - - if (localQname != null && dataSchemaNode instanceof DataNodeContainer) { - final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode) - .getDataChildByName(localQname); - dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent) - .node(child.getQName()).build(); - assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode() - .equals(child)); - } else { - assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode() - .equals(dataSchemaNode)); - } - assertTrue(nnContext.getInstanceIdentifierContext() - .getInstanceIdentifier().equals(dataNodeIdent)); - assertNotNull(NormalizedNodes.findNode(nnContext.getData(), - dataNodeIdent)); + private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode, + final NormalizedNodeContext nnContext, + final YangInstanceIdentifier dataNodeIdent) { + assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode()); + assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier()); + assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java index 46bea7a75c..bb55b45221 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java @@ -8,13 +8,14 @@ package org.opendaylight.controller.sal.rest.impl.test.providers; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; - +import com.google.common.base.Optional; +import com.google.common.collect.Sets; import java.io.InputStream; - +import java.net.URI; import javax.ws.rs.core.MediaType; - import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlNormalizedNodeBodyReader; @@ -27,25 +28,25 @@ import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import com.google.common.base.Optional; - /** - * sal-rest-connector org.opendaylight.controller.sal.rest.impl.test.providers + * sal-rest-connector + * org.opendaylight.controller.sal.rest.impl.test.providers * * * * @author Vaclav Demcak * - * Created: Mar 7, 2015 + * Created: Mar 7, 2015 */ public class TestXmlBodyReader extends AbstractBodyReaderTest { private final XmlNormalizedNodeBodyReader xmlBodyReader; private static SchemaContext schemaContext; - public TestXmlBodyReader() throws NoSuchFieldException, SecurityException { + public TestXmlBodyReader () throws NoSuchFieldException, SecurityException { super(); xmlBodyReader = new XmlNormalizedNodeBodyReader(); } @@ -56,10 +57,8 @@ public class TestXmlBodyReader extends AbstractBodyReaderTest { } @BeforeClass - public static void initialization() throws NoSuchFieldException, - SecurityException { - schemaContext = schemaContextLoader("/instanceidentifier/yang", - schemaContext); + public static void initialization() throws NoSuchFieldException, SecurityException { + schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext); schemaContext = schemaContextLoader("/modules", schemaContext); schemaContext = schemaContextLoader("/invoke-rpc", schemaContext); controllerContext.setSchemas(schemaContext); @@ -67,45 +66,90 @@ public class TestXmlBodyReader extends AbstractBodyReaderTest { @Test public void moduleDataTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()); final String uri = "instance-identifier-module:cont"; mockBodyReader(uri, xmlBodyReader, false); final InputStream inputStream = TestXmlBodyReader.class .getResourceAsStream("/instanceidentifier/xml/xmldata.xml"); - final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); } @Test public void moduleSubContainerDataPutTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName); + final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName); final String uri = "instance-identifier-module:cont/cont1"; mockBodyReader(uri, xmlBodyReader, false); final InputStream inputStream = TestXmlBodyReader.class .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml"); - final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, - "cont1"); + checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII); } @Test public void moduleSubContainerDataPostTest() throws Exception { - final DataSchemaNode dataSchemaNode = schemaContext - .getDataChildByName("cont"); + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1"); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName); final String uri = "instance-identifier-module:cont"; mockBodyReader(uri, xmlBodyReader, true); final InputStream inputStream = TestXmlBodyReader.class .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml"); - final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); - checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); + } + + @Test + public void moduleSubContainerAugmentDataPostTest() throws Exception { + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next(); + QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment"); + YangInstanceIdentifier.AugmentationIdentifier augII = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(contAugmentQName)); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()) + .node(augII).node(contAugmentQName); + final String uri = "instance-identifier-module:cont"; + mockBodyReader(uri, xmlBodyReader, true); + final InputStream inputStream = TestXmlBodyReader.class + .getResourceAsStream("/instanceidentifier/xml/xml_augment_container.xml"); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); + checkNormalizedNodeContext(returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); + } + + @Test + public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception { + final DataSchemaNode dataSchemaNode = schemaContext.getDataChildByName("cont"); + final Module augmentModule = schemaContext.findModuleByNamespace(new URI("augment:module")).iterator().next(); + QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1"); + QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2"); + final QName containerQName = QName.create(augmentChoice1QName, "case-choice-case-container1"); + YangInstanceIdentifier.AugmentationIdentifier augChoice1II = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(augmentChoice1QName)); + YangInstanceIdentifier.AugmentationIdentifier augChoice2II = new YangInstanceIdentifier.AugmentationIdentifier( + Sets.newHashSet(augmentChoice2QName)); + final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()) + .node(augChoice1II).node(augmentChoice1QName).node(augChoice2II).node(augmentChoice2QName) + .node(containerQName); + final String uri = "instance-identifier-module:cont"; + mockBodyReader(uri, xmlBodyReader, true); + final InputStream inputStream = TestXmlBodyReader.class + .getResourceAsStream("/instanceidentifier/xml/xml_augment_choice_container.xml"); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); + checkNormalizedNodeContext(returnValue); + checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII); } @Test @@ -114,45 +158,26 @@ public class TestXmlBodyReader extends AbstractBodyReaderTest { mockBodyReader(uri, xmlBodyReader, true); final InputStream inputStream = TestXmlBodyReader.class .getResourceAsStream("/invoke-rpc/xml/rpc-input.xml"); - final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, - null, null, mediaType, null, inputStream); + final NormalizedNodeContext returnValue = xmlBodyReader + .readFrom(null, null, null, mediaType, null, inputStream); checkNormalizedNodeContext(returnValue); final ContainerNode contNode = (ContainerNode) returnValue.getData(); - final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(QName - .create(contNode.getNodeType(), "lf")); - final Optional> leafDataNode = contNode - .getChild(yangleaf.getLastPathArgument()); + final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(QName.create(contNode.getNodeType(), "lf")); + final Optional> leafDataNode = contNode.getChild(yangleaf.getLastPathArgument()); assertTrue(leafDataNode.isPresent()); - assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().getValue() - .toString())); + assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().getValue().toString())); } - private void checkExpectValueNormalizeNodeContext( - final DataSchemaNode dataSchemaNode, + private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode, final NormalizedNodeContext nnContext) { checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null); } - private void checkExpectValueNormalizeNodeContext( - final DataSchemaNode dataSchemaNode, - final NormalizedNodeContext nnContext, final String localQname) { - YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier - .of(dataSchemaNode.getQName()); - - if (localQname != null && dataSchemaNode instanceof DataNodeContainer) { - final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode) - .getDataChildByName(localQname); - dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent) - .node(child.getQName()).build(); - assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode() - .equals(child)); - } else { - assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode() - .equals(dataSchemaNode)); - } - assertTrue(nnContext.getInstanceIdentifierContext() - .getInstanceIdentifier().equals(dataNodeIdent)); - assertNotNull(NormalizedNodes.findNode(nnContext.getData(), - dataNodeIdent)); + private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode, + final NormalizedNodeContext nnContext, + final YangInstanceIdentifier dataNodeIdent) { + assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode()); + assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier()); + assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java index 9c5de08c5c..15d5f97f9c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java @@ -204,7 +204,7 @@ public class BrokerFacadeTest { when(rwTransaction.submit()).thenReturn(expFuture); final CheckedFuture actualFuture = brokerFacade.commitConfigurationDataPost( - (SchemaContext)null, YangInstanceIdentifier.builder().build(), dummyNode); + (SchemaContext)null, instanceID, dummyNode); assertSame("commitConfigurationDataPost", expFuture, actualFuture); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_choice_container.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_choice_container.json new file mode 100644 index 0000000000..e64e00ed32 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_choice_container.json @@ -0,0 +1,5 @@ +{ + "augment-module:case-choice-case-container1": { + "augment-module:case-choice-case-leaf1": "stryng" + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_container.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_container.json new file mode 100644 index 0000000000..e2532f2876 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/json_augment_container.json @@ -0,0 +1,5 @@ +{ + "augment-module:cont-augment": { + "augment-module:leaf1": "stryng" + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml new file mode 100644 index 0000000000..d73b3008b6 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml @@ -0,0 +1,3 @@ + + stryng + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_container.xml new file mode 100644 index 0000000000..6b35e9e967 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xml_augment_container.xml @@ -0,0 +1,3 @@ + + stryng + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang index 67b0086ee3..c918ef98ad 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module.yang @@ -1,13 +1,13 @@ module augment-module { - namespace "augment:module"; + namespace "augment:module"; prefix "amodule"; - + import instance-identifier-module {prefix imodule; revision-date 2014-01-17;} - - revision 2014-01-17 { + + revision 2014-01-17 { } - + augment "/imodule:cont/imodule:cont1" { list lst11 { key "keyvalue111 keyvalue112"; @@ -17,7 +17,47 @@ module augment-module { leaf keyvalue112 { type string; } - } + } + } + + augment "/imodule:cont" { + container cont-augment { + leaf leaf1 { + type string; + } + } } - -} \ No newline at end of file + + augment "/imodule:cont" { + choice augment-choice1 { + case case1 { + container case-container1 { + leaf case-leaf1 { + type string; + } + } + } + + case case2 { + container case-container2 { + leaf case-leaf2 { + type string; + } + } + } + } + } + + augment "/imodule:cont/augment-choice1/case1" { + choice augment-choice2 { + case case11 { + container case-choice-case-container1 { + leaf case-choice-case-leaf1 { + type string; + } + } + } + } + } + +} -- 2.36.6