checkNotNull(parent);
checkNotNull(parentSchema);
+ List<String> longestPathToElementViaChoiceCase = new ArrayList<>();
for (Node<?> child : parent.getChildren()) {
- DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
- if (childSchema == null) {
- throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName()
- + "\" is not conform to schema");
+ Deque<String> choiceCasePathStack = new ArrayDeque<>(longestPathToElementViaChoiceCase);
+ SchemaLocation schemaLocation = findFirstSchemaForNode(child, parentSchema.getChildNodes(),
+ choiceCasePathStack);
+
+ if (schemaLocation == null) {
+ if (!choiceCasePathStack.isEmpty()) {
+ throw new UnsupportedDataTypeException("On choice-case path " + choiceCasePathStack
+ + " wasn't found data schema for " + child.getNodeType().getLocalName());
+ } else {
+ throw new UnsupportedDataTypeException("Probably the data node \""
+ + child.getNodeType().getLocalName() + "\" is not conform to schema");
+ }
}
+ longestPathToElementViaChoiceCase = resolveLongerPath(longestPathToElementViaChoiceCase,
+ schemaLocation.getLocation());
+
+ DataSchemaNode childSchema = schemaLocation.getSchema();
+
if (childSchema instanceof ContainerSchemaNode) {
Preconditions.checkState(child instanceof CompositeNode,
"Data representation of Container should be CompositeNode - " + child.getNodeType());
}
for (Node<?> child : parent.getChildren()) {
- DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
+ SchemaLocation schemaLocation = findFirstSchemaForNode(child, parentSchema.getChildNodes(),
+ new ArrayDeque<>(longestPathToElementViaChoiceCase));
+
+ DataSchemaNode childSchema = schemaLocation.getSchema();
if (childSchema instanceof LeafListSchemaNode) {
foundLeafLists.remove((LeafListSchemaNode) childSchema);
} else if (childSchema instanceof ListSchemaNode) {
}
}
- private DataSchemaNode findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
+ private List<String> resolveLongerPath(List<String> l1, List<String> l2) {
+ return l1.size() > l2.size() ? l1 : l2;
+ }
+
+ private SchemaLocation findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode,
+ Deque<String> pathIterator) {
+ Map<String, ChoiceNode> choiceSubnodes = new HashMap<>();
for (DataSchemaNode dsn : dataSchemaNode) {
- if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
- return dsn;
+ if (dsn instanceof ChoiceNode) {
+ choiceSubnodes.put(dsn.getQName().getLocalName(), (ChoiceNode) dsn);
+ } else if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
+ return new SchemaLocation(dsn);
+ }
+ }
+
+ for (ChoiceNode choiceSubnode : choiceSubnodes.values()) {
+ if ((!pathIterator.isEmpty() && pathIterator.peekLast().equals(choiceSubnode.getQName().getLocalName()))
+ || pathIterator.isEmpty()) {
+ String pathPartChoice = pathIterator.pollLast();
+ for (ChoiceCaseNode concreteCase : choiceSubnode.getCases()) {
+ if ((!pathIterator.isEmpty() && pathIterator.peekLast().equals(
+ concreteCase.getQName().getLocalName()))
+ || pathIterator.isEmpty()) {
+ String pathPartCase = pathIterator.pollLast();
+ SchemaLocation schemaLocation = findFirstSchemaForNode(node, concreteCase.getChildNodes(),
+ pathIterator);
+ if (schemaLocation != null) {
+ schemaLocation.addPathPart(concreteCase.getQName().getLocalName());
+ schemaLocation.addPathPart(choiceSubnode.getQName().getLocalName());
+ return schemaLocation;
+ }
+ if (pathPartCase != null) {
+ pathIterator.addLast(pathPartCase);
+ }
+ }
+ }
+ if (pathPartChoice != null) {
+ pathIterator.addLast(pathPartChoice);
+ }
}
}
return null;
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import java.util.*;
+
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class SchemaLocation {
+ final private List<String> location = new ArrayList<>();
+ final private DataSchemaNode schema;
+
+ public SchemaLocation(DataSchemaNode schema) {
+ this.schema = schema;
+ }
+
+ DataSchemaNode getSchema() {
+ return schema;
+ }
+
+ List<String> getLocation() {
+ return location;
+ }
+
+ SchemaLocation addPathPart(String partOfPath) {
+ location.add(partOfPath);
+ return this;
+ }
+
+}
static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath,
String outputPath, String searchedModuleName, String searchedDataSchemaName) {
- String jsonResult = null;
- Set<Module> modules = null;
+ Set<Module> modules = resolveModules(yangPath);
+ Module module = resolveModule(searchedModuleName, modules);
+ DataSchemaNode dataSchemaNode = resolveDataSchemaNode(module, searchedDataSchemaName);
try {
- modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath());
- } catch (FileNotFoundException e) {
+ return writeCompNodeWithSchemaContextToJson(compositeNode, outputPath, modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // TODO Auto-generated catch block
e.printStackTrace();
}
- assertNotNull("modules can't be null.", modules);
+ return null;
+ }
+
+ static Module resolveModule(String searchedModuleName, Set<Module> modules) {
+ assertNotNull("modules can't be null.", modules);
Module module = null;
if (searchedModuleName != null) {
for (Module m : modules) {
} else if (modules.size() == 1) {
module = modules.iterator().next();
}
- assertNotNull("Module is missing", module);
+ return module;
+ }
- assertNotNull("Composite node can't be null", compositeNode);
+ static Set<Module> resolveModules(String yangPath) {
+ Set<Module> modules = null;
+
+ try {
+ modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath());
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ return modules;
+ }
+
+ static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) {
+ assertNotNull("Module is missing", module);
- StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE;
- ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
DataSchemaNode dataSchemaNode = null;
if (searchedDataSchemaName != null) {
for (DataSchemaNode dsn : module.getChildNodes()) {
} else if (module.getChildNodes().size() == 1) {
dataSchemaNode = module.getChildNodes().iterator().next();
}
+ return dataSchemaNode;
+ }
+
+ static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, String outputPath,
+ Set<Module> modules, DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException {
+ String jsonResult;
+
assertNotNull(dataSchemaNode);
- // SchemaContextUtil.
+ assertNotNull("Composite node can't be null", compositeNode);
+ ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
- ControllerContext controllerContext = ControllerContext.getInstance();
- controllerContext.setSchemas(loadSchemaContext(modules));
- StructuredData structuredData = new StructuredData(compositeNode, dataSchemaNode);
- try {
- structuredDataToJsonProvider.writeTo(structuredData, null, null, null, null, null, byteArrayOS);
- } catch (WebApplicationException | IOException e) {
- e.printStackTrace();
- }
- assertFalse("Returning JSON string can't be empty for node " + dataSchemaNode.getQName().getLocalName(),
- byteArrayOS.toString().isEmpty());
+ ControllerContext contContext = ControllerContext.getInstance();
+ contContext.setSchemas(loadSchemaContext(modules));
+
+ StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE;
+ structuredDataToJsonProvider.writeTo(new StructuredData(compositeNode, dataSchemaNode), null, null, null, null,
+ null, byteArrayOS);
jsonResult = byteArrayOS.toString();
try {
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.*;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+public class ToJsonChoiceCaseTest {
+
+ private static Set<Module> modules;
+ private static DataSchemaNode dataSchemaNode;
+
+ @BeforeClass
+ public static void initialization() {
+ modules = TestUtils.resolveModules("/yang-to-json-conversion/choice");
+ Module module = TestUtils.resolveModule(null, modules);
+ dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null);
+
+ }
+
+ /**
+ * Test when some data are in one case node and other in another. Exception
+ * expected!!
+ */
+ @Test
+ public void compNodeDataOnVariousChoiceCasePathTest() {
+ boolean exceptionCatched = false;
+ try {
+ TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_various_path.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (UnsupportedDataTypeException e) {
+ exceptionCatched = true;
+
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+
+ assertTrue(exceptionCatched);
+
+ }
+
+ /**
+ * Test when second level data are red first, then first and at the end
+ * third level. Level represents pass through couple choice-case
+ */
+ @Ignore
+ @Test
+ public void compNodeDataWithRandomOrderAccordingLevel() {
+ try {
+ String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_random_level.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+
+ /**
+ * Test when element from no first case is used
+ */
+ @Ignore
+ @Test
+ public void compNodeDataNoFirstCase() {
+ try {
+ String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_no_first_case.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+
+ /**
+ * Test when element in case is list
+ */
+ @Ignore
+ @Test
+ public void compNodeDataAsList() {
+ try {
+ String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_list.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+
+ /**
+ * Test when element in case is container
+ */
+ @Ignore
+ @Test
+ public void compNodeDataAsContainer() {
+ try {
+ String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_container.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+
+ /**
+ * Test when element in case is container
+ */
+ @Ignore
+ @Test
+ public void compNodeDataAsLeafList() {
+ try {
+ String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_leaflist.xml"),
+ "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+
+}
--- /dev/null
+module choice-case-test {
+ namespace "choice:case:test";
+
+ prefix "chcatst";
+ revision 2013-11-27 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+
+ choice choi1 {
+ case a1 {
+ leaf lf1a {
+ type uint16;
+ }
+ choice choi1a {
+ case aa1 {
+ leaf lf1aa {
+ type string;
+ }
+ choice choi1aa {
+ case aaa1 {
+ leaf lf1aaa {
+ type string;
+ }
+ }
+ case aab1 {
+ leaf lf1aab {
+ type string;
+ }
+ }
+ }
+ }
+ case ab1 {
+ leaf lf1ab {
+ type string;
+ }
+ }
+ }
+ }
+ case b1 {
+ list lst1b {
+ leaf lf11b {
+ type string;
+ }
+ }
+ }
+ case c1 {
+ container cont1c {
+ leaf lf11c {
+ type string;
+ }
+ }
+ }
+ case d1 {
+ leaf-list lflst1d {
+ type string;
+ }
+ }
+ }
+
+ choice choi2 {
+ case a2 {
+ leaf lf2a {
+ type string;
+ }
+ }
+ case b2 {
+ leaf lf2b {
+ type string;
+ }
+ }
+ }
+
+/* equal identifiers in various cases are illegal 7.9.2 rfc6020 */
+/*
+ choice choi3 {
+ case 3a {
+ leaf lf3a {
+ type string;
+ }
+ }
+ case 3b {
+ leaf lf3b {
+ type string;
+ }
+ }
+ }
+*/
+
+ }
+
+
+
+}
\ No newline at end of file
--- /dev/null
+<cont>
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <lflst1d>lflst1d_1 val</lflst1d>
+ <lflst1d>lflst1d_2 val</lflst1d>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <lst1b>
+ <lf11b>lf11b_1 val</lf11b>
+ </lst1b>
+ <lst1b>
+ <lf11b>lf11b_2 val</lf11b>
+ </lst1b>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab val</lf1ab>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1aaa>lf1aaa val</lf1aaa>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab value</lf1ab>
+</cont>
\ No newline at end of file