Merge "Choice and case resolving in JSON output"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / rest / impl / JsonMapper.java
index 073b24e033914a1fe2e227d6e78c351b1c75b8a0..36b46a171cde4706a1b7e22d17ed4c7e00ccdc90 100644 (file)
@@ -7,9 +7,8 @@ import java.util.*;
 
 import javax.activation.UnsupportedDataTypeException;
 
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yangtools.yang.data.api.*;
 import org.opendaylight.yangtools.yang.model.api.*;
 import org.opendaylight.yangtools.yang.model.api.type.*;
 
@@ -48,13 +47,27 @@ class JsonMapper {
         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());
@@ -84,7 +97,10 @@ class JsonMapper {
         }
 
         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) {
@@ -93,24 +109,60 @@ class JsonMapper {
         }
     }
 
-    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;
     }
 
     private void writeContainer(JsonWriter writer, CompositeNode node, ContainerSchemaNode schema) throws IOException {
-        writer.name(node.getNodeType().getLocalName());
+        writeName(node, schema, writer);
         writer.beginObject();
         writeChildrenOfParent(writer, node, schema);
         writer.endObject();
     }
 
-    private void writeList(JsonWriter writer, CompositeNode nodeParent, CompositeNode node, ListSchemaNode schema) throws IOException {
-        writer.name(node.getNodeType().getLocalName());
+    private void writeList(JsonWriter writer, CompositeNode nodeParent, CompositeNode node, ListSchemaNode schema)
+            throws IOException {
+        writeName(node, schema, writer);
         writer.beginArray();
 
         if (nodeParent != null) {
@@ -129,8 +181,9 @@ class JsonMapper {
         writer.endArray();
     }
 
-    private void writeLeafList(JsonWriter writer, CompositeNode nodeParent, SimpleNode<?> node, LeafListSchemaNode schema) throws IOException {
-        writer.name(node.getNodeType().getLocalName());
+    private void writeLeafList(JsonWriter writer, CompositeNode nodeParent, SimpleNode<?> node,
+            LeafListSchemaNode schema) throws IOException {
+        writeName(node, schema, writer);
         writer.beginArray();
 
         List<SimpleNode<?>> nodeLeafLists = nodeParent.getSimpleNodesByName(node.getNodeType());
@@ -142,17 +195,14 @@ class JsonMapper {
     }
 
     private void writeLeaf(JsonWriter writer, SimpleNode<?> node, LeafSchemaNode schema) throws IOException {
-        writer.name(node.getNodeType().getLocalName());
+        writeName(node, schema, writer);
         writeValueOfNodeByType(writer, node, schema.getType());
     }
 
     private void writeValueOfNodeByType(JsonWriter writer, SimpleNode<?> node, TypeDefinition<?> type)
             throws IOException {
-        if (!(node.getValue() instanceof String)) {
-            throw new IllegalStateException("Value in SimpleNode should be type String");
-        }
 
-        String value = (String) node.getValue();
+        String value = String.valueOf(node.getValue());
         // TODO check Leafref, InstanceIdentifierTypeDefinition,
         // IdentityrefTypeDefinition, UnionTypeDefinition
         TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
@@ -168,7 +218,7 @@ class JsonMapper {
         } else if (baseType instanceof EmptyTypeDefinition) {
             writeEmptyDataTypeToJson(writer);
         } else {
-            writer.value(value != null ? value : "");
+            writer.value(value.equals("null") ? "" : value);
         }
     }
 
@@ -244,6 +294,19 @@ class JsonMapper {
         return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type;
     }
 
+    private void writeName(Node<?> node, DataSchemaNode schema, JsonWriter writer) throws IOException {
+        String nameForOutput = node.getNodeType().getLocalName();
+        if (schema.isAugmenting()) {
+            ControllerContext contContext = ControllerContext.getInstance();
+            CharSequence moduleName;
+            moduleName = contContext.toRestconfIdentifier(schema.getQName());
+            if (moduleName != null) {
+                nameForOutput = moduleName.toString();
+            }
+        }
+        writer.name(nameForOutput);
+    }
+
     private static final class NumberForJsonWriter extends Number {
 
         private static final long serialVersionUID = -3147729419814417666L;