blob: cf4e690d171409e7e3f9845314e092fc7d5a071e [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.protocol.restconf.server.utils.parser.json;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import org.onosproject.protocol.restconf.server.utils.exceptions.JsonParseException;
import org.onosproject.protocol.restconf.server.utils.parser.api.JsonListener;
import org.onosproject.protocol.restconf.server.utils.parser.api.NormalizedYangNode;
import org.onosproject.yms.ydt.YdtBuilder;
import org.onosproject.yms.ydt.YdtContext;
import org.slf4j.Logger;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Stack;
import static com.fasterxml.jackson.databind.node.JsonNodeType.ARRAY;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils.buildNormalizedNode;
import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_NODE;
import static org.onosproject.yms.ydt.YdtType.SINGLE_INSTANCE_NODE;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Represents default implementation of codec JSON listener.
*/
public class JsonToYdtListener implements JsonListener {
private static final String INPUT_FIELD_NAME = "input";
private static final String COLON = ":";
private static final int INPUT_FIELD_LENGTH = 2;
private static final String E_UNSUP_TYPE = "Unsupported node type %s " +
"field name is %s fieldName";
private static final String EMPTY_STRING = "null";
private Logger log = getLogger(getClass());
private YdtBuilder ydtBuilder;
private NormalizedYangNode defaultMultiInsNode;
private Stack<NormalizedYangNode> nameStack = new Stack<>();
private YdtContext rpcModule;
private boolean isListArray = false;
/**
* Creates a listener for the process of a Json Object, the listener will
* try to transfer the JSON object to a Ydt builder.
*
* @param ydtBuilder the YDT builder to build a YDT object
*/
public JsonToYdtListener(YdtBuilder ydtBuilder) {
this.ydtBuilder = ydtBuilder;
}
@Override
public void enterJsonNode(String fieldName, JsonNode node) {
if (isNullOrEmpty(fieldName)) {
if (defaultMultiInsNode != null) {
ydtBuilder.addChild(defaultMultiInsNode.getName(),
defaultMultiInsNode.getNamespace(),
MULTI_INSTANCE_NODE);
}
return;
}
NormalizedYangNode normalizedNode = buildNormalizedNode(fieldName);
JsonNodeType nodeType = node.getNodeType();
switch (nodeType) {
case OBJECT:
processObjectNode(normalizedNode);
break;
case ARRAY:
processArrayNode(normalizedNode, node);
break;
//TODO for now, just process the following three node type
case STRING:
case NUMBER:
case BOOLEAN:
processLeafNode(normalizedNode, node.asText());
break;
case BINARY:
case MISSING:
case NULL:
case POJO:
log.debug("Unimplemented node type {}", nodeType);
break;
default:
throw new JsonParseException(String.format(E_UNSUP_TYPE,
nodeType, fieldName));
}
}
@Override
public void exitJsonNode(JsonNode jsonNode) {
if (isListArray) {
isListArray = false;
ydtBuilder.traverseToParent();
return;
}
if (jsonNode.getNodeType() == ARRAY) {
//check empty before pop
if (nameStack.empty()) {
return;
}
nameStack.pop();
//check empty after pop
if (nameStack.empty()) {
return;
}
defaultMultiInsNode = nameStack.get(nameStack.size() - 1);
return;
}
ydtBuilder.traverseToParent();
}
private void processObjectNode(NormalizedYangNode node) {
ydtBuilder.addChild(node.getName(), node.getNamespace(),
SINGLE_INSTANCE_NODE);
}
private void processLeafNode(NormalizedYangNode node, String value) {
String leafValue = value.equalsIgnoreCase(EMPTY_STRING) ? null : value;
ydtBuilder.addLeaf(node.getName(), node.getNamespace(), leafValue);
}
private void processArrayNode(NormalizedYangNode normalizedNode,
JsonNode node) {
ArrayNode arrayNode = (ArrayNode) node;
if (arrayNode.size() == 0) {
return;
}
Set<String> sets = new LinkedHashSet<>();
Iterator<JsonNode> elements = arrayNode.elements();
boolean isLeafList = true;
while (elements.hasNext()) {
JsonNode element = elements.next();
JsonNodeType eleType = element.getNodeType();
if (eleType == JsonNodeType.STRING ||
eleType == JsonNodeType.NUMBER ||
eleType == JsonNodeType.BOOLEAN) {
sets.add(element.asText());
} else {
isLeafList = false;
}
}
if (isLeafList) {
//leaf-list
ydtBuilder.addLeaf(normalizedNode.getName(),
normalizedNode.getNamespace(), sets);
isListArray = true;
} else {
defaultMultiInsNode = normalizedNode;
nameStack.push(defaultMultiInsNode);
}
}
}