| /* |
| * 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.trace("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); |
| } |
| } |
| } |