Bug 1003: Restconf - remove whitespace on input
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / rest / impl / JsonReader.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.rest.impl;
9
10 import java.io.InputStream;
11 import java.io.InputStreamReader;
12 import java.net.URI;
13 import java.util.Map.Entry;
14 import java.util.Set;
15
16 import org.opendaylight.controller.sal.rest.impl.RestUtil.PrefixMapingFromJson;
17 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
18 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
19 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
20 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
21
22 import com.google.common.collect.Lists;
23 import com.google.gson.JsonElement;
24 import com.google.gson.JsonObject;
25 import com.google.gson.JsonParser;
26 import com.google.gson.JsonPrimitive;
27
28 class JsonReader {
29
30     public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedFormatException {
31         JsonParser parser = new JsonParser();
32
33         JsonElement rootElement = parser.parse(new InputStreamReader(entityStream));
34         if (!rootElement.isJsonObject()) {
35             throw new UnsupportedFormatException("Root element of Json has to be Object");
36         }
37
38         Set<Entry<String, JsonElement>> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet();
39         if (entrySetsOfRootJsonObject.size() != 1) {
40             throw new UnsupportedFormatException("Json Object should contain one element");
41         } else {
42             Entry<String, JsonElement> childEntry = Lists.newArrayList(entrySetsOfRootJsonObject).get(0);
43             String firstElementName = childEntry.getKey();
44             JsonElement firstElementType = childEntry.getValue();
45             if (firstElementType.isJsonObject()) { // container in yang
46                 return createStructureWithRoot(firstElementName, firstElementType.getAsJsonObject());
47             }
48             if (firstElementType.isJsonArray()) { // list in yang
49                 if (firstElementType.getAsJsonArray().size() == 1) {
50                     JsonElement firstElementInArray = firstElementType.getAsJsonArray().get(0);
51                     if (firstElementInArray.isJsonObject()) {
52                         return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
53                     }
54                     throw new UnsupportedFormatException(
55                             "Array as the first element in Json Object can have only Object element");
56                 }
57             }
58             throw new UnsupportedFormatException(
59                     "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
60         }
61     }
62
63     private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) {
64         CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName),
65                 getLocalNameFor(rootObjectName));
66         for (Entry<String, JsonElement> childOfFirstNode : rootObject.entrySet()) {
67             addChildToParent(childOfFirstNode.getKey(), childOfFirstNode.getValue(), firstNode);
68         }
69         return firstNode;
70     }
71
72     private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
73         if (childType.isJsonObject()) {
74             CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName));
75             parent.addValue(child);
76             for (Entry<String, JsonElement> childOfChild : childType.getAsJsonObject().entrySet()) {
77                 addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child);
78             }
79         } else if (childType.isJsonArray()) {
80             if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) {
81                 parent.addValue(new EmptyNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)));
82
83             } else {
84                 for (JsonElement childOfChildType : childType.getAsJsonArray()) {
85                     addChildToParent(childName, childOfChildType, parent);
86                 }
87             }
88         } else if (childType.isJsonPrimitive()) {
89             JsonPrimitive childPrimitive = childType.getAsJsonPrimitive();
90             String value = childPrimitive.getAsString().trim();
91             parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName),
92                     resolveValueOfElement(value)));
93         }
94     }
95
96     private URI getNamespaceFor(String jsonElementName) {
97         String[] moduleNameAndLocalName = jsonElementName.split(":");
98         // it is not "moduleName:localName"
99         if (moduleNameAndLocalName.length != 2) {
100             return null;
101         }
102         return URI.create(moduleNameAndLocalName[0]);
103     }
104
105     private String getLocalNameFor(String jsonElementName) {
106         String[] moduleNameAndLocalName = jsonElementName.split(":");
107         // it is not "moduleName:localName"
108         if (moduleNameAndLocalName.length != 2) {
109             return jsonElementName;
110         }
111         return moduleNameAndLocalName[1];
112     }
113
114     private Object resolveValueOfElement(String value) {
115         // it could be instance-identifier Built-In Type
116         if (value.startsWith("/")) {
117             IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
118             if (resolvedValue != null) {
119                 return resolvedValue;
120             }
121         }
122         // it could be identityref Built-In Type
123         URI namespace = getNamespaceFor(value);
124         if (namespace != null) {
125             return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null,value);
126         }
127         // it is not "prefix:value" but just "value"
128         return value;
129     }
130
131 }