/* * 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.JsonPrimitive; import com.google.gson.stream.JsonReader; 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.gson.JsonParser; 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; class JsonToCompositeNodeReader { private static final Logger LOG = LoggerFactory.getLogger(JsonReader.class); private static final Splitter COLON_SPLITTER = Splitter.on(':'); private JsonToCompositeNodeReader() { } public static CompositeNodeWrapper read(final InputStream entityStream) throws UnsupportedFormatException { JsonParser parser = new JsonParser(); JsonElement rootElement = parser.parse(new JsonReader(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"); } Set> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet(); if (entrySetsOfRootJsonObject.size() != 1) { throw new UnsupportedFormatException("Json Object should contain one element"); } Entry 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."); } private static CompositeNodeWrapper createStructureWithRoot(final String rootObjectName, final JsonObject rootObject) { CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName), getLocalNameFor(rootObjectName)); for (Entry childOfFirstNode : rootObject.entrySet()) { addChildToParent(childOfFirstNode.getKey(), childOfFirstNode.getValue(), firstNode); } return firstNode; } private static void addChildToParent(final String childName, final JsonElement childType, final CompositeNodeWrapper parent) { if (childType.isJsonObject()) { CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)); parent.addValue(child); for (Entry 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(getNamespaceFor(childName), getLocalNameFor(childName))); } else { for (JsonElement childOfChildType : childType.getAsJsonArray()) { addChildToParent(childName, childOfChildType, parent); } } } else if (childType.isJsonPrimitive()) { JsonPrimitive childPrimitive = childType.getAsJsonPrimitive(); String value = childPrimitive.getAsString().trim(); parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName), resolveValueOfElement(value))); } else { LOG.debug("Ignoring unhandled child type {}", childType); } } private static URI getNamespaceFor(final String jsonElementName) { final Iterator 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 null; } private static String getLocalNameFor(final String jsonElementName) { final Iterator 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 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); } // it is not "prefix:value" but just "value" return value; } }