[ONOS-5397]fixbug:NBI Error for complicate list inside container
1.if a array's children are all not container node,
it's a leaf-list in yang, should treat differently;
2.for a array, the field name should push into a stack,
and then pop when exit the array
3. add namespace info for yangnode
4. process the exception of null array node
Change-Id: Ia7b0c25ab1ccea393b97a0fcf59187663348de3b
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/NormalizedYangNode.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/NormalizedYangNode.java
new file mode 100755
index 0000000..31a1423
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/NormalizedYangNode.java
@@ -0,0 +1,56 @@
+/*
+ * 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.api;
+
+/**
+ * Abstraction of an entity which represents a simple YANG node. This entity
+ * is usually described by a path segment in URI, or a field name in a JSON
+ * node.
+ */
+public class NormalizedYangNode {
+ private final String namespace;
+ private final String name;
+
+ /**
+ * Creates an instance of normalized YANG node using the supplied information.
+ *
+ * @param namespace namespace of a YANG node
+ * @param name name of a YANG node
+ */
+ public NormalizedYangNode(String namespace, String name) {
+ this.namespace = namespace;
+ this.name = name;
+ }
+
+ /**
+ * Returns the namespace info of a YANG node.
+ *
+ * @return namespace info
+ */
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /**
+ * Returns the name of a YANG node.
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/JsonToYdtListener.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/JsonToYdtListener.java
old mode 100644
new mode 100755
index 4a130f7..7c59e11
--- a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/JsonToYdtListener.java
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/JsonToYdtListener.java
@@ -21,6 +21,7 @@
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;
@@ -28,9 +29,11 @@
import java.util.HashSet;
import java.util.Iterator;
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;
@@ -49,8 +52,10 @@
private Logger log = getLogger(getClass());
private YdtBuilder ydtBuilder;
- private String defaultMultiInsNodeName;
+ 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
@@ -65,27 +70,29 @@
@Override
public void enterJsonNode(String fieldName, JsonNode node) {
if (isNullOrEmpty(fieldName)) {
- if (!isNullOrEmpty(defaultMultiInsNodeName)) {
- ydtBuilder.addChild(defaultMultiInsNodeName, null,
+ 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(fieldName);
+ processObjectNode(normalizedNode);
break;
case ARRAY:
- processArrayNode(fieldName, node);
+ processArrayNode(normalizedNode, node);
break;
//TODO for now, just process the following three node type
case STRING:
case NUMBER:
case BOOLEAN:
- ydtBuilder.addLeaf(fieldName, null, node.asText());
+ processLeafNode(normalizedNode, node.asText());
break;
case BINARY:
@@ -103,41 +110,40 @@
@Override
public void exitJsonNode(JsonNode jsonNode) {
- if (jsonNode.getNodeType() == ARRAY) {
+ if (jsonNode.getNodeType() == ARRAY && nameStack.empty()) {
return;
}
+
+ if (jsonNode.getNodeType() == ARRAY && !isListArray) {
+ nameStack.pop();
+ if (nameStack.empty()) {
+ return;
+ }
+ defaultMultiInsNode = nameStack.get(nameStack.size() - 1);
+ return;
+ }
+ if (isListArray) {
+ isListArray = false;
+ }
+
ydtBuilder.traverseToParent();
- YdtContext curNode = ydtBuilder.getCurNode();
- //if the current node is the RPC node, then should go to the father
- //for we have enter the RPC node and Input node at the same time
- //and the input is the only child of RPC node.
+ }
- if (curNode == null) {
+ private void processObjectNode(NormalizedYangNode node) {
+ ydtBuilder.addChild(node.getName(), node.getNamespace(),
+ SINGLE_INSTANCE_NODE);
+ }
+
+ private void processLeafNode(NormalizedYangNode node, String value) {
+ ydtBuilder.addLeaf(node.getName(), node.getNamespace(), value);
+ }
+
+ private void processArrayNode(NormalizedYangNode normalizedNode,
+ JsonNode node) {
+ ArrayNode arrayNode = (ArrayNode) node;
+ if (arrayNode.size() == 0) {
return;
}
- String name = curNode.getName();
- if (rpcModule != null && name.equals(rpcModule.getName())) {
- ydtBuilder.traverseToParent();
- }
- }
-
- private void processObjectNode(String fieldName) {
- String[] segments = fieldName.split(COLON);
- Boolean isLastInput = segments.length == INPUT_FIELD_LENGTH &&
- segments[INPUT_FIELD_LENGTH - 1].equals(INPUT_FIELD_NAME);
- int first = 0;
- int second = 1;
- if (isLastInput) {
- ydtBuilder.addChild(segments[first], null, SINGLE_INSTANCE_NODE);
- rpcModule = ydtBuilder.getCurNode();
- ydtBuilder.addChild(segments[second], null, SINGLE_INSTANCE_NODE);
- } else {
- ydtBuilder.addChild(fieldName, null, SINGLE_INSTANCE_NODE);
- }
- }
-
- private void processArrayNode(String fieldName, JsonNode node) {
- ArrayNode arrayNode = (ArrayNode) node;
Set<String> sets = new HashSet<>();
Iterator<JsonNode> elements = arrayNode.elements();
boolean isLeafList = true;
@@ -155,9 +161,12 @@
}
if (isLeafList) {
//leaf-list
- ydtBuilder.addLeaf(fieldName, null, sets);
+ ydtBuilder.addLeaf(normalizedNode.getName(),
+ normalizedNode.getNamespace(), sets);
+ isListArray = true;
} else {
- this.defaultMultiInsNodeName = fieldName;
+ defaultMultiInsNode = normalizedNode;
+ nameStack.push(defaultMultiInsNode);
}
}
}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/ParserUtils.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/ParserUtils.java
old mode 100644
new mode 100755
index fa8b133..bc959f0
--- a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/ParserUtils.java
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/ParserUtils.java
@@ -21,6 +21,7 @@
import com.google.common.collect.Lists;
import org.onosproject.protocol.restconf.server.utils.exceptions.JsonParseException;
import org.onosproject.protocol.restconf.server.utils.parser.api.JsonBuilder;
+import org.onosproject.protocol.restconf.server.utils.parser.api.NormalizedYangNode;
import org.onosproject.yms.ydt.YdtBuilder;
import org.onosproject.yms.ydt.YdtContext;
import org.onosproject.yms.ydt.YdtContextOperationType;
@@ -142,25 +143,6 @@
return builder;
}
- private static YdtBuilder addModule(YdtBuilder builder, String path) {
- String moduleName = getPreSegment(path, COLON);
- if (moduleName == null) {
- throw new JsonParseException(ERROR_MODULE_MSG);
- }
- builder.addChild(moduleName, null, YdtType.SINGLE_INSTANCE_NODE);
- return builder;
- }
-
- private static YdtBuilder addNode(String path, YdtBuilder builder,
- YdtContextOperationType opType) {
- String nodeName = getLatterSegment(path, COLON);
- builder.addChild(nodeName,
- null,
- YdtType.SINGLE_INSTANCE_NODE,
- opType);
- return builder;
- }
-
private static YdtBuilder addListOrLeafList(String path,
YdtBuilder builder,
YdtContextOperationType opType) {
@@ -188,6 +170,25 @@
return builder;
}
+ private static YdtBuilder addModule(YdtBuilder builder, String path) {
+ String moduleName = getPreSegment(path, COLON);
+ if (moduleName == null) {
+ throw new JsonParseException(ERROR_MODULE_MSG);
+ }
+ builder.addChild(moduleName, null, YdtType.SINGLE_INSTANCE_NODE);
+ return builder;
+ }
+
+ private static YdtBuilder addNode(String path, YdtBuilder builder,
+ YdtContextOperationType opType) {
+ String nodeName = getLatterSegment(path, COLON);
+ builder.addChild(nodeName,
+ null,
+ YdtType.SINGLE_INSTANCE_NODE,
+ opType);
+ return builder;
+ }
+
/**
* Returns the previous segment of a path which is separated by a split char.
* For example:
@@ -256,4 +257,18 @@
paths + "': ", e);
}
}
+
+ /**
+ * Converts a field to a simple YANG node description which contains the
+ * namespace and name information.
+ *
+ * @param field field name of a JSON body, or a segment of a URI
+ * in a request of RESTCONF
+ * @return a simple normalized YANG node
+ */
+ public static NormalizedYangNode buildNormalizedNode(String field) {
+ String namespace = getPreSegment(field, COLON);
+ String name = getLatterSegment(field, COLON);
+ return new NormalizedYangNode(namespace, name);
+ }
}