Merge "Improved translation from XML to Json"
authorEd Warnicke <eaw@cisco.com>
Fri, 8 Nov 2013 15:28:52 +0000 (15:28 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 8 Nov 2013 15:28:52 +0000 (15:28 +0000)
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/JsonMapper.xtend [deleted file]

diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
new file mode 100644 (file)
index 0000000..55751e5
--- /dev/null
@@ -0,0 +1,190 @@
+package org.opendaylight.controller.sal.rest.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+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.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
+
+import com.google.gson.stream.JsonWriter;
+
+class JsonMapper {
+    
+    private final Set<LeafListSchemaNode> foundLeafLists = new HashSet<>();
+    private final Set<ListSchemaNode> foundLists = new HashSet<>();
+    
+    public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException {
+        writer.beginObject();
+        writeChildrenOfParent(writer, data, schema);
+        writer.endObject();
+        foundLeafLists.clear();
+        foundLists.clear();
+    }
+
+    private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema) throws IOException {
+        checkNotNull(parent);
+        checkNotNull(parentSchema);
+        
+        for (Node<?> child : parent.getChildren()) {
+            DataSchemaNode childSchema = findSchemaForNode(child, parentSchema.getChildNodes());
+            if (childSchema instanceof ContainerSchemaNode) {
+                writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
+            } else if (childSchema instanceof ListSchemaNode) {
+                if (!foundLists.contains(childSchema)) {
+                    foundLists.add((ListSchemaNode) childSchema);
+                    writeList(writer, (CompositeNode) child, (ListSchemaNode) childSchema);
+                }
+            } else if (childSchema instanceof LeafListSchemaNode) {
+                if (!foundLeafLists.contains(childSchema)) {
+                    foundLeafLists.add((LeafListSchemaNode) childSchema);
+                    writeLeafList(writer, (SimpleNode<?>) child, (LeafListSchemaNode) childSchema);
+                }
+            } else if (childSchema instanceof LeafSchemaNode) {
+                writeLeaf(writer, (SimpleNode<?>) child, (LeafSchemaNode) childSchema);
+            }
+        }
+        
+        for (Node<?> child : parent.getChildren()) {
+            DataSchemaNode childSchema = findSchemaForNode(child, parentSchema.getChildNodes());
+            if (childSchema instanceof LeafListSchemaNode) {
+                foundLeafLists.remove((LeafListSchemaNode) childSchema);
+            } else if (childSchema instanceof ListSchemaNode) {
+                foundLists.remove((ListSchemaNode) childSchema);
+            }
+        }
+    }
+    
+    private DataSchemaNode findSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
+        for (DataSchemaNode dsn : dataSchemaNode) {
+            if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
+                return dsn;
+            }
+        }
+        return null;
+    }
+    
+    private void writeContainer(JsonWriter writer, CompositeNode node, ContainerSchemaNode schema) throws IOException {
+        writer.name(node.getNodeType().getLocalName());
+        writer.beginObject();
+        writeChildrenOfParent(writer, node, schema);
+        writer.endObject();
+    }
+    
+    private void writeList(JsonWriter writer, CompositeNode node, ListSchemaNode schema) throws IOException {
+            writer.name(node.getNodeType().getLocalName());
+            writer.beginArray();
+            
+            if (node.getParent() != null) {
+                CompositeNode parent = node.getParent();
+                List<CompositeNode> nodeLists = parent.getCompositesByName(node.getNodeType());
+                for (CompositeNode nodeList : nodeLists) {
+                    writer.beginObject();
+                    writeChildrenOfParent(writer, nodeList, schema);
+                    writer.endObject();
+                }
+            } else {
+                writer.beginObject();
+                writeChildrenOfParent(writer, node, schema);
+                writer.endObject();
+            }
+            
+            writer.endArray();
+    }
+    
+    private void writeLeafList(JsonWriter writer, SimpleNode<?> node, LeafListSchemaNode schema) throws IOException {
+            writer.name(node.getNodeType().getLocalName());
+            writer.beginArray();
+            
+            CompositeNode parent = node.getParent();
+            List<SimpleNode<?>> nodeLeafLists = parent.getSimpleNodesByName(node.getNodeType());
+            for (SimpleNode<?> nodeLeafList : nodeLeafLists) {
+                writeValueOfNodeByType(writer, nodeLeafList, schema.getType());
+            }
+            
+            writer.endArray();
+    }
+    
+    private void writeLeaf(JsonWriter writer, SimpleNode<?> node, LeafSchemaNode schema) throws IOException {
+        writer.name(node.getNodeType().getLocalName());
+        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();
+        // TODO check Leafref, InstanceIdentifierTypeDefinition, IdentityrefTypeDefinition, UnionTypeDefinition
+        if (type.getBaseType() != null) {
+            writeValueOfNodeByType(writer, node, type.getBaseType());
+        } else if (type instanceof InstanceIdentifierTypeDefinition) {
+            writer.value(((InstanceIdentifierTypeDefinition) type).getPathStatement().toString());
+        } else if (type instanceof DecimalTypeDefinition 
+                || type instanceof IntegerTypeDefinition
+                || type instanceof UnsignedIntegerTypeDefinition) {
+            writer.value(new NumberForJsonWriter(value));
+        } else if (type instanceof BooleanTypeDefinition) {
+            writer.value(Boolean.parseBoolean(value));
+        } else if (type instanceof EmptyTypeDefinition) {
+            writer.value("[null]");
+        } else {
+            writer.value(value);
+        }
+    }
+    
+    private static final class NumberForJsonWriter extends Number {
+        
+        private static final long serialVersionUID = -3147729419814417666L;
+        private final String value;
+        
+        public NumberForJsonWriter(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public int intValue() {
+            throw new IllegalStateException("Should not be invoked");
+        }
+
+        @Override
+        public long longValue() {
+            throw new IllegalStateException("Should not be invoked");
+        }
+
+        @Override
+        public float floatValue() {
+            throw new IllegalStateException("Should not be invoked");
+        }
+
+        @Override
+        public double doubleValue() {
+            throw new IllegalStateException("Should not be invoked");
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+        
+    }
+
+}
index 97ad3ef69d887b6fcda025c12ffa95921fc70857..cc6d449523671cfdca429ea1bb31779726a57b9c 100644 (file)
@@ -24,8 +24,7 @@ public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNo
 
     @Override
     public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
-        // TODO Auto-generated method stub
-        return false;
+        return true;
     }
 
     @Override
index 608cdcd94341f5d8a37fc1ec520f2667b4b62028..b0e1e03c6c2715c0b99f271619d387f721d39884 100644 (file)
@@ -7,8 +7,6 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
-import java.util.List;
-import java.util.Set;
 
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
@@ -19,18 +17,7 @@ import javax.ws.rs.ext.Provider;
 
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
-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.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
 
 import com.google.gson.stream.JsonWriter;
 
@@ -41,8 +28,7 @@ public enum StructuredDataToJsonProvider implements MessageBodyWriter<Structured
     
     @Override
     public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
-        // TODO Auto-generated method stub
-        return false;
+        return true;
     }
 
     @Override
@@ -56,81 +42,9 @@ public enum StructuredDataToJsonProvider implements MessageBodyWriter<Structured
             throws IOException, WebApplicationException {
         JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
         writer.setIndent("    ");
-        writer.beginObject();
-        convertNodeToJsonAccordingToSchema(writer, t.getData(), t.getSchema());
-        writer.endObject();
+        JsonMapper jsonMapper = new JsonMapper();
+        jsonMapper.write(writer, t.getData(), (DataNodeContainer) t.getSchema());
+        writer.flush();
     }
-
-    private void convertNodeToJsonAccordingToSchema(JsonWriter writer, Node<?> node, DataSchemaNode dataSchemaNode) throws IOException {
-        if (node instanceof CompositeNode) {
-            if (!(dataSchemaNode instanceof DataNodeContainer)) {
-                throw new IllegalStateException("CompositeNode should be represented as DataNodeContainer");
-            }
-            if (dataSchemaNode instanceof ContainerSchemaNode) {
-                writer.name(node.getNodeType().getLocalName());
-                writer.beginObject();
-                String listName = "";
-                for (Node<?> n : ((CompositeNode) node).getChildren()) {
-                    DataSchemaNode foundDataSchemaNode = findSchemaForNode(n, ((DataNodeContainer) dataSchemaNode).getChildNodes());
-                    if (foundDataSchemaNode instanceof ListSchemaNode) {
-                        if (listName.equals(n.getNodeType().getLocalName())) {
-                            continue;
-                        }
-                        listName = n.getNodeType().getLocalName();
-                    }
-                    convertNodeToJsonAccordingToSchema(writer, n, foundDataSchemaNode);
-                }
-                writer.endObject();
-            } else if (dataSchemaNode instanceof ListSchemaNode) {
-                writer.name(node.getNodeType().getLocalName());
-                writer.beginArray();
-                List<Node<?>> nodeSiblings = node.getParent().getChildren();
-                for (Node<?> nodeSibling : nodeSiblings) {
-                    if (nodeSibling.getNodeType().getLocalName().equals(node.getNodeType().getLocalName())) {
-                        DataSchemaNode schemaForNodeSibling = findSchemaForNode(nodeSibling,
-                                ((DataNodeContainer) dataSchemaNode.getParent()).getChildNodes());
-                        writer.beginObject();
-                        for (Node<?> child : ((CompositeNode) nodeSibling).getChildren()) {
-                            DataSchemaNode schemaForChild = findSchemaForNode(child,
-                                    ((DataNodeContainer) schemaForNodeSibling).getChildNodes());
-                            convertNodeToJsonAccordingToSchema(writer, child, schemaForChild);
-                        }
-                        writer.endObject();
-                    }
-                }
-                writer.endArray();
-            }
-        } else if (node instanceof SimpleNode<?>) {
-            if (!(dataSchemaNode instanceof LeafSchemaNode)) {
-                throw new IllegalStateException("SimpleNode should should be represented as LeafSchemaNode");
-            }
-            writeLeaf(writer, (LeafSchemaNode) dataSchemaNode, (SimpleNode<?>) node);
-        }
-    }
-
-    private DataSchemaNode findSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
-        for (DataSchemaNode dsn : dataSchemaNode) {
-            if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
-                return dsn;
-            }
-        }
-        return null;
-    }
-
-    private void writeLeaf(JsonWriter writer, LeafSchemaNode leafSchemaNode, SimpleNode<?> data) throws IOException {
-        TypeDefinition<?> type = leafSchemaNode.getType();
-
-        writer.name(data.getNodeType().getLocalName());
-
-        if (type instanceof DecimalTypeDefinition) {
-            writer.value((Double.valueOf((String) data.getValue())).doubleValue());
-        } else if (type instanceof IntegerTypeDefinition) {
-            writer.value((Integer.valueOf((String) data.getValue())).intValue());
-        } else if (type instanceof EmptyTypeDefinition) {
-            writer.value("[null]");
-        } else {
-            writer.value(String.valueOf(data.getValue()));
-        }
-    }
-
+    
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/JsonMapper.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/JsonMapper.xtend
deleted file mode 100644 (file)
index 7584b64..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.opendaylight.controller.sal.restconf.impl
-
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-
-class JsonMapper {
-    
-    @Property
-    ControllerContext controllerContext
-    
-    def convert(DataSchemaNode schema, CompositeNode data) {
-        return ""
-    }
-    
-}
\ No newline at end of file