Merge "Complete implementation of DataChangeListenerProxy"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / rest / impl / JsonReader.java
index 83e2d20d0e74334a8b138846e7fcd3396902c23f..e94554061800cb8ae918dc59a598fea980cac972 100644 (file)
@@ -1,27 +1,51 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.sal.rest.impl;
 
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterators;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URI;
+import java.util.Iterator;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.opendaylight.controller.sal.rest.impl.RestUtil.PrefixMapingFromJson;
 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Lists;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonPrimitive;
+final class JsonReader {
+    private static final Logger LOG = LoggerFactory.getLogger(JsonReader.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+
+    private JsonReader() {
 
-class JsonReader {
+    }
 
-    public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedFormatException {
+    public static CompositeNodeWrapper read(final InputStream entityStream) throws UnsupportedFormatException {
         JsonParser parser = new JsonParser();
 
         JsonElement rootElement = parser.parse(new InputStreamReader(entityStream));
+        if (rootElement.isJsonNull()) {
+            //no content, so return null to indicate no input
+            return null;
+        }
+
         if (!rootElement.isJsonObject()) {
             throw new UnsupportedFormatException("Root element of Json has to be Object");
         }
@@ -29,49 +53,49 @@ class JsonReader {
         Set<Entry<String, JsonElement>> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet();
         if (entrySetsOfRootJsonObject.size() != 1) {
             throw new UnsupportedFormatException("Json Object should contain one element");
-        } else {
-            Entry<String, JsonElement> childEntry = Lists.newArrayList(entrySetsOfRootJsonObject).get(0);
-            String firstElementName = childEntry.getKey();
-            JsonElement firstElementType = childEntry.getValue();
-            if (firstElementType.isJsonObject()) { // container in yang
-                return createStructureWithRoot(firstElementName, firstElementType.getAsJsonObject());
-            }
-            if (firstElementType.isJsonArray()) { // list in yang
-                if (firstElementType.getAsJsonArray().size() == 1) {
-                    JsonElement firstElementInArray = firstElementType.getAsJsonArray().get(0);
-                    if (firstElementInArray.isJsonObject()) {
-                        return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
-                    }
-                    throw new UnsupportedFormatException(
-                            "Array as the first element in Json Object can have only Object element");
+        }
+
+        Entry<String, JsonElement> childEntry = entrySetsOfRootJsonObject.iterator().next();
+        String firstElementName = childEntry.getKey();
+        JsonElement firstElementType = childEntry.getValue();
+        if (firstElementType.isJsonObject()) {
+            // container in yang
+            return createStructureWithRoot(firstElementName, firstElementType.getAsJsonObject());
+        }
+        if (firstElementType.isJsonArray()) {
+            // list in yang
+            if (firstElementType.getAsJsonArray().size() == 1) {
+                JsonElement firstElementInArray = firstElementType.getAsJsonArray().get(0);
+                if (firstElementInArray.isJsonObject()) {
+                    return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
                 }
+                throw new UnsupportedFormatException(
+                        "Array as the first element in Json Object can have only Object element");
             }
-            throw new UnsupportedFormatException(
-                    "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
         }
+        throw new UnsupportedFormatException(
+                "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
     }
 
-    private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) {
-        CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFrom(rootObjectName),
-                getLocalNameFrom(rootObjectName));
+    private static CompositeNodeWrapper createStructureWithRoot(final String rootObjectName, final JsonObject rootObject) {
+        CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName),
+                getLocalNameFor(rootObjectName));
         for (Entry<String, JsonElement> childOfFirstNode : rootObject.entrySet()) {
             addChildToParent(childOfFirstNode.getKey(), childOfFirstNode.getValue(), firstNode);
         }
         return firstNode;
     }
 
-    private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
+    private static void addChildToParent(final String childName, final JsonElement childType, final CompositeNodeWrapper parent) {
         if (childType.isJsonObject()) {
-            CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFrom(childName),
-                    getLocalNameFrom(childName));
+            CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName));
             parent.addValue(child);
             for (Entry<String, JsonElement> childOfChild : childType.getAsJsonObject().entrySet()) {
                 addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child);
             }
         } else if (childType.isJsonArray()) {
             if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) {
-                parent.addValue(new EmptyNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName)));
-
+                parent.addValue(new EmptyNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)));
             } else {
                 for (JsonElement childOfChildType : childType.getAsJsonArray()) {
                     addChildToParent(childName, childOfChildType, parent);
@@ -79,25 +103,52 @@ class JsonReader {
             }
         } else if (childType.isJsonPrimitive()) {
             JsonPrimitive childPrimitive = childType.getAsJsonPrimitive();
-            String value = childPrimitive.getAsString();
-            parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value));
+            String value = childPrimitive.getAsString().trim();
+            parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName),
+                    resolveValueOfElement(value)));
+        } else {
+            LOG.debug("Ignoring unhandled child type {}", childType);
         }
     }
 
-    private URI getNamespaceFrom(String jsonElementName) {
-        int indexOfDelimeter = jsonElementName.lastIndexOf(':');
-        if (indexOfDelimeter == -1) {
-            return null;
+    private static URI getNamespaceFor(final String jsonElementName) {
+        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
+
+        // The string needs to me in form "moduleName:localName"
+        if (it.hasNext()) {
+            final String maybeURI = it.next();
+            if (Iterators.size(it) == 1) {
+                return URI.create(maybeURI);
+            }
         }
-        return URI.create(jsonElementName.substring(0, indexOfDelimeter));
+
+        return null;
+    }
+
+    private static String getLocalNameFor(final String jsonElementName) {
+        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
+
+        // The string needs to me in form "moduleName:localName"
+        final String ret = Iterators.get(it, 1, null);
+        return ret != null && !it.hasNext() ? ret : jsonElementName;
     }
 
-    private String getLocalNameFrom(String jsonElementName) {
-        int indexOfDelimeter = jsonElementName.lastIndexOf(':');
-        if (indexOfDelimeter == -1) {
-            return jsonElementName;
+    private static Object resolveValueOfElement(final String value) {
+        // it could be instance-identifier Built-In Type
+        if (!value.isEmpty() && value.charAt(0) == '/') {
+            IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
+            if (resolvedValue != null) {
+                return resolvedValue;
+            }
+        }
+
+        // it could be identityref Built-In Type
+        URI namespace = getNamespaceFor(value);
+        if (namespace != null) {
+            return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null,value);
         }
-        return jsonElementName.substring(indexOfDelimeter + 1, jsonElementName.length());
+        // it is not "prefix:value" but just "value"
+        return value;
     }
 
 }