blob: 11181167f3edd42ac73beb1e0148fb389708342e [file] [log] [blame]
chengfanc58d4be2016-09-20 10:33:12 +08001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.protocol.restconf.server.utils.parser.json;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.JsonNodeType;
22import org.onosproject.protocol.restconf.server.utils.exceptions.JsonParseException;
23import org.onosproject.protocol.restconf.server.utils.parser.api.JsonListener;
chengfan7b2a60b2016-10-08 20:27:15 +080024import org.onosproject.protocol.restconf.server.utils.parser.api.NormalizedYangNode;
chengfanc58d4be2016-09-20 10:33:12 +080025import org.onosproject.yms.ydt.YdtBuilder;
26import org.onosproject.yms.ydt.YdtContext;
27import org.slf4j.Logger;
28
29import java.util.HashSet;
30import java.util.Iterator;
31import java.util.Set;
chengfan7b2a60b2016-10-08 20:27:15 +080032import java.util.Stack;
chengfanc58d4be2016-09-20 10:33:12 +080033
34import static com.fasterxml.jackson.databind.node.JsonNodeType.ARRAY;
35import static com.google.common.base.Strings.isNullOrEmpty;
chengfan7b2a60b2016-10-08 20:27:15 +080036import static org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils.buildNormalizedNode;
chengfanc58d4be2016-09-20 10:33:12 +080037import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_NODE;
38import static org.onosproject.yms.ydt.YdtType.SINGLE_INSTANCE_NODE;
39import static org.slf4j.LoggerFactory.getLogger;
40
41/**
42 * Represents default implementation of codec JSON listener.
43 */
44public class JsonToYdtListener implements JsonListener {
45
46 private static final String INPUT_FIELD_NAME = "input";
47 private static final String COLON = ":";
48 private static final int INPUT_FIELD_LENGTH = 2;
49 private static final String E_UNSUP_TYPE = "Unsupported node type %s " +
50 "field name is %s fieldName";
51
52 private Logger log = getLogger(getClass());
53
54 private YdtBuilder ydtBuilder;
chengfan7b2a60b2016-10-08 20:27:15 +080055 private NormalizedYangNode defaultMultiInsNode;
56 private Stack<NormalizedYangNode> nameStack = new Stack<>();
chengfanc58d4be2016-09-20 10:33:12 +080057 private YdtContext rpcModule;
chengfan7b2a60b2016-10-08 20:27:15 +080058 private boolean isListArray = false;
chengfanc58d4be2016-09-20 10:33:12 +080059
60 /**
61 * Creates a listener for the process of a Json Object, the listener will
62 * try to transfer the JSON object to a Ydt builder.
63 *
64 * @param ydtBuilder the YDT builder to build a YDT object
65 */
66 public JsonToYdtListener(YdtBuilder ydtBuilder) {
67 this.ydtBuilder = ydtBuilder;
68 }
69
70 @Override
71 public void enterJsonNode(String fieldName, JsonNode node) {
72 if (isNullOrEmpty(fieldName)) {
chengfan7b2a60b2016-10-08 20:27:15 +080073 if (defaultMultiInsNode != null) {
74 ydtBuilder.addChild(defaultMultiInsNode.getName(),
75 defaultMultiInsNode.getNamespace(),
chengfanc58d4be2016-09-20 10:33:12 +080076 MULTI_INSTANCE_NODE);
77 }
78 return;
79 }
chengfan7b2a60b2016-10-08 20:27:15 +080080 NormalizedYangNode normalizedNode = buildNormalizedNode(fieldName);
chengfanc58d4be2016-09-20 10:33:12 +080081 JsonNodeType nodeType = node.getNodeType();
82 switch (nodeType) {
83 case OBJECT:
chengfan7b2a60b2016-10-08 20:27:15 +080084 processObjectNode(normalizedNode);
chengfanc58d4be2016-09-20 10:33:12 +080085 break;
86
87 case ARRAY:
chengfan7b2a60b2016-10-08 20:27:15 +080088 processArrayNode(normalizedNode, node);
chengfanc58d4be2016-09-20 10:33:12 +080089 break;
90
91 //TODO for now, just process the following three node type
92 case STRING:
93 case NUMBER:
94 case BOOLEAN:
chengfan7b2a60b2016-10-08 20:27:15 +080095 processLeafNode(normalizedNode, node.asText());
chengfanc58d4be2016-09-20 10:33:12 +080096 break;
97
98 case BINARY:
99 case MISSING:
100 case NULL:
101 case POJO:
102 log.debug("Unimplemented node type {}", nodeType);
103 break;
104
105 default:
106 throw new JsonParseException(String.format(E_UNSUP_TYPE,
107 nodeType, fieldName));
108 }
109 }
110
111 @Override
112 public void exitJsonNode(JsonNode jsonNode) {
chengfan0c32d712016-10-11 21:03:23 +0800113
114 if (isListArray) {
115 isListArray = false;
116 ydtBuilder.traverseToParent();
chengfanc58d4be2016-09-20 10:33:12 +0800117 return;
118 }
chengfan7b2a60b2016-10-08 20:27:15 +0800119
chengfan0c32d712016-10-11 21:03:23 +0800120 if (jsonNode.getNodeType() == ARRAY) {
121 //check empty before pop
122 if (nameStack.empty()) {
123 return;
124 }
chengfan7b2a60b2016-10-08 20:27:15 +0800125 nameStack.pop();
chengfan0c32d712016-10-11 21:03:23 +0800126 //check empty after pop
chengfan7b2a60b2016-10-08 20:27:15 +0800127 if (nameStack.empty()) {
128 return;
129 }
130 defaultMultiInsNode = nameStack.get(nameStack.size() - 1);
131 return;
132 }
chengfan7b2a60b2016-10-08 20:27:15 +0800133
chengfanc58d4be2016-09-20 10:33:12 +0800134 ydtBuilder.traverseToParent();
chengfan7b2a60b2016-10-08 20:27:15 +0800135 }
chengfanc58d4be2016-09-20 10:33:12 +0800136
chengfan7b2a60b2016-10-08 20:27:15 +0800137 private void processObjectNode(NormalizedYangNode node) {
138 ydtBuilder.addChild(node.getName(), node.getNamespace(),
139 SINGLE_INSTANCE_NODE);
140 }
141
142 private void processLeafNode(NormalizedYangNode node, String value) {
143 ydtBuilder.addLeaf(node.getName(), node.getNamespace(), value);
144 }
145
146 private void processArrayNode(NormalizedYangNode normalizedNode,
147 JsonNode node) {
148 ArrayNode arrayNode = (ArrayNode) node;
149 if (arrayNode.size() == 0) {
chengfanc58d4be2016-09-20 10:33:12 +0800150 return;
151 }
chengfanc58d4be2016-09-20 10:33:12 +0800152 Set<String> sets = new HashSet<>();
153 Iterator<JsonNode> elements = arrayNode.elements();
154 boolean isLeafList = true;
155 while (elements.hasNext()) {
156 JsonNode element = elements.next();
157 JsonNodeType eleType = element.getNodeType();
158
159 if (eleType == JsonNodeType.STRING ||
160 eleType == JsonNodeType.NUMBER ||
161 eleType == JsonNodeType.BOOLEAN) {
162 sets.add(element.asText());
163 } else {
164 isLeafList = false;
165 }
166 }
167 if (isLeafList) {
168 //leaf-list
chengfan7b2a60b2016-10-08 20:27:15 +0800169 ydtBuilder.addLeaf(normalizedNode.getName(),
170 normalizedNode.getNamespace(), sets);
171 isListArray = true;
chengfanc58d4be2016-09-20 10:33:12 +0800172 } else {
chengfan7b2a60b2016-10-08 20:27:15 +0800173 defaultMultiInsNode = normalizedNode;
174 nameStack.push(defaultMultiInsNode);
chengfanc58d4be2016-09-20 10:33:12 +0800175 }
176 }
177}