[ONOS-5012] implement RESTconf server
- fix javadoc longer than 80 char limit
- fix javadoc that missing @params
- chain calls to StringBuilder.append()
- combine constant strings in place
Change-Id: Ie2ef4fd4c19e955ad2d5a5584f5017a842abb790
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/JsonParseException.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/JsonParseException.java
new file mode 100644
index 0000000..cd178c5
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/JsonParseException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.exceptions;
+
+/**
+ * Represents class of errors related to Json parse utils.
+ */
+public class JsonParseException extends RuntimeException {
+
+ /**
+ * Constructs an exception with the specified message.
+ *
+ * @param message the message describing the specific nature of the error
+ */
+ public JsonParseException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an exception with the specified message and the underlying
+ * cause.
+ *
+ * @param message the message describing the specific nature of the error
+ * @param cause the underlying cause of this error
+ */
+ public JsonParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/YdtParseException.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/YdtParseException.java
new file mode 100644
index 0000000..c2e121b
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/YdtParseException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.exceptions;
+
+/**
+ * Represents class of errors related to YDT parse utils.
+ */
+public class YdtParseException extends RuntimeException {
+ /**
+ * Constructs an exception with the specified message.
+ *
+ * @param message the message describing the specific nature of the error
+ */
+ public YdtParseException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an exception with the specified message and the underlying
+ * cause.
+ *
+ * @param message the message describing the specific nature of the error
+ * @param cause the underlying cause of this error
+ */
+ public YdtParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/package-info.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/package-info.java
new file mode 100644
index 0000000..508bca0
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/exceptions/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Parse utils custom exceptions.
+ */
+package org.onosproject.protocol.restconf.server.utils.exceptions;
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonBuilder.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonBuilder.java
new file mode 100644
index 0000000..f56422f
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.Set;
+
+/**
+ * Abstraction of an entity which provides interfaces to build and obtain JSON
+ * data tree.
+ */
+public interface JsonBuilder {
+
+ /**
+ * Adds a to half (a left brace/bracket and the field name) of a JSON
+ * object/array to the JSON tree. This method is used by protocols which
+ * knows the nature (object/array) of node.
+ *
+ * @param fieldName name of child to be added
+ * @param nodeType the type of the child
+ */
+ void addNodeTopHalf(String fieldName, JsonNodeType nodeType);
+
+ /**
+ * Adds a child with value and a comma to the JSON tree.
+ * Protocols unaware of nature of node (single/multiple) will use it to add
+ * both single instance and multi instance node. Protocols aware of nature
+ * of node will use it for single instance value node addition.
+ *
+ * @param fieldName name of child to be added
+ * @param value the type of the child
+ */
+ void addNodeWithValueTopHalf(String fieldName, String value);
+
+ /**
+ * Adds a child with list of values to JSON data tree. This method is
+ * used by protocols which knows the nature (object/array) of node for
+ * ArrayNode addition.
+ *
+ * @param fieldName name of child to be added
+ * @param sets the value list of the child
+ */
+ void addNodeWithSetTopHalf(String fieldName, Set<String> sets);
+
+ /**
+ * Adds the bottom half(a right brace/bracket) of a JSON object/array to
+ * the JSON tree. for the text, a comma should be taken out.
+ *
+ * @param nodeType the type of the child
+ */
+ void addNodeBottomHalf(JsonNodeType nodeType);
+
+ /**
+ * Returns the JSON tree after build operations in the format of string.
+ *
+ * @return the final string JSON tree after build operations
+ */
+ String getTreeString();
+
+ /**
+ * Returns the JSON tree after build operations in the format of ObjectNode.
+ *
+ * @return the final ObjectNode JSON tree after build operations
+ */
+ ObjectNode getTreeNode();
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonListener.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonListener.java
new file mode 100644
index 0000000..7432dd3
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonListener.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Abstraction of an entity which provide call back methods which are called
+ * by JSON walker while walking the JSON data tree. This interface needs to be
+ * implemented by protocol implementing listener's based call backs while JSON
+ * walk.
+ */
+public interface JsonListener {
+
+ /**
+ * Callback invoked during a node entry.
+ * All the related information about the node can be obtain from the JSON
+ * object.
+ *
+ * @param fieldName the field name of the JSON Node value
+ * @param node the JsonNode which is walked through
+ */
+ void enterJsonNode(String fieldName, JsonNode node);
+
+ /**
+ * Callback invoked during a node exit.
+ * All the related information about the node can be obtain from the JSON
+ * node.
+ *
+ * @param jsonNode JSON node which has been walked through
+ */
+ void exitJsonNode(JsonNode jsonNode);
+
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonWalker.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonWalker.java
new file mode 100644
index 0000000..59ce2ab
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/JsonWalker.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Abstraction of an entity which provides interfaces for Json walk.
+ * This interface serve as common tools for anyone who needs to parse
+ * the json node with depth-first algorithm.
+ */
+public interface JsonWalker {
+
+ /**
+ * Walks the JSON data tree. Protocols implements JSON listener service
+ * and walks JSON tree with input as implemented object. JSON walker
+ * provides call backs to implemented methods. For the original json
+ * node(come from NB), there is a field name which is something like the
+ * module name of a YANG model. If not, the fieldName can be null.
+ *
+ * @param jsonListener Json listener implemented by the user
+ * @param fieldName the original object node field
+ * @param node the json node which needs to be walk
+ */
+ void walk(JsonListener jsonListener, String fieldName, ObjectNode node);
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/package-info.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/package-info.java
new file mode 100644
index 0000000..51d28df
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provider json related process interface.
+ */
+package org.onosproject.protocol.restconf.server.utils.parser.api;
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonBuilder.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonBuilder.java
new file mode 100644
index 0000000..b5f2911
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonBuilder.java
@@ -0,0 +1,177 @@
+/*
+ * 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.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.protocol.restconf.server.utils.exceptions.JsonParseException;
+import org.onosproject.protocol.restconf.server.utils.parser.api.JsonBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Represents implementation of interfaces to build and obtain JSON data tree.
+ */
+public class DefaultJsonBuilder implements JsonBuilder {
+
+ private static final String LEFT_BRACE = "{";
+ private static final String RIGHT_BRACE = "}";
+ private static final String LEFT_BRACKET = "[";
+ private static final String RIGHT_BRACKET = "]";
+ private static final String COMMA = ",";
+ private static final String COLON = ":";
+ private static final String QUOTE = "\"";
+ private static final String E_UNSUP_TYPE = "Unsupported node type %s " +
+ "field name is %s fieldName";
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ private StringBuilder treeString;
+
+ /**
+ * Creates a Default Json Builder with a specific root name.
+ *
+ * @param rootName the start string of the Json builder
+ */
+ public DefaultJsonBuilder(String rootName) {
+ checkNotNull(rootName);
+ treeString = new StringBuilder(rootName);
+ }
+
+ /**
+ * Creates a Default Json Builder with a default root name.
+ */
+ public DefaultJsonBuilder() {
+ treeString = new StringBuilder(LEFT_BRACE);
+ }
+
+ @Override
+ public void addNodeTopHalf(String fieldName, JsonNodeType nodeType) {
+
+ appendField(fieldName);
+
+ switch (nodeType) {
+ case OBJECT:
+ treeString.append(LEFT_BRACE);
+ break;
+ case ARRAY:
+ treeString.append(LEFT_BRACKET);
+ break;
+ default:
+ throw new JsonParseException(String.format(E_UNSUP_TYPE,
+ nodeType, fieldName));
+ }
+ }
+
+ @Override
+ public void addNodeWithValueTopHalf(String fieldName, String value) {
+ if (isNullOrEmpty(fieldName)) {
+ return;
+ }
+ appendField(fieldName);
+ if (value.isEmpty()) {
+ return;
+ }
+ treeString.append(QUOTE)
+ .append(value)
+ .append(QUOTE + COMMA);
+ }
+
+ @Override
+ public void addNodeWithSetTopHalf(String fieldName, Set<String> sets) {
+ if (isNullOrEmpty(fieldName)) {
+ return;
+ }
+ appendField(fieldName);
+ treeString.append(LEFT_BRACKET);
+ for (String el : sets) {
+ treeString.append(QUOTE)
+ .append(el)
+ .append(QUOTE + COMMA);
+ }
+ }
+
+ @Override
+ public void addNodeBottomHalf(JsonNodeType nodeType) {
+
+ switch (nodeType) {
+ case OBJECT:
+ removeCommaIfExist();
+ treeString.append(RIGHT_BRACE + COMMA);
+ break;
+
+ case ARRAY:
+ removeCommaIfExist();
+ treeString.append(RIGHT_BRACKET + COMMA);
+ break;
+
+ case BINARY:
+ case BOOLEAN:
+ case MISSING:
+ case NULL:
+ case NUMBER:
+ case POJO:
+ case STRING:
+ log.debug("Unimplemented node type {}", nodeType);
+ break;
+
+ default:
+ throw new JsonParseException("Unsupported json node type " +
+ nodeType);
+ }
+ }
+
+ @Override
+ public String getTreeString() {
+ removeCommaIfExist();
+ return treeString.append(RIGHT_BRACE).toString();
+ }
+
+ @Override
+ public ObjectNode getTreeNode() {
+ ObjectNode node = null;
+ try {
+ node = (ObjectNode) (new ObjectMapper()).readTree(getTreeString());
+ } catch (IOException e) {
+ log.error("Parse json string failed {}", e.getMessage());
+ }
+ return node;
+ }
+
+
+ private void appendField(String fieldName) {
+ if (!isNullOrEmpty(fieldName)) {
+ treeString.append(QUOTE)
+ .append(fieldName)
+ .append(QUOTE + COLON);
+ }
+ }
+
+ private void removeCommaIfExist() {
+ int lastIndex = treeString.length() - 1;
+ if (treeString.charAt(lastIndex) == COMMA.charAt(0)) {
+ treeString.deleteCharAt(lastIndex);
+ }
+ }
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonWalker.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonWalker.java
new file mode 100644
index 0000000..c1802ac
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/DefaultJsonWalker.java
@@ -0,0 +1,109 @@
+/*
+ * 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.ObjectNode;
+import org.onosproject.protocol.restconf.server.utils.parser.api.JsonWalker;
+import org.onosproject.protocol.restconf.server.utils.parser.api.JsonListener;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Represents implementation of JSON walk, which walks the JSON object node.
+ */
+public class DefaultJsonWalker implements JsonWalker {
+ @Override
+ public void walk(JsonListener jsonListener, String fieldName,
+ ObjectNode objectNode) {
+
+ //enter the object node, the original ObjectNode should have a module
+ //name as fieldName.
+ jsonListener.enterJsonNode(fieldName, objectNode);
+ //the node has no children, then exist and return.
+ if (!objectNode.isContainerNode()) {
+ jsonListener.exitJsonNode(objectNode);
+ return;
+ }
+
+ Iterator<Map.Entry<String, JsonNode>> fields = objectNode.fields();
+ while (fields.hasNext()) {
+ //get the children entry of the node
+ Map.Entry<String, JsonNode> currentChild = fields.next();
+ String key = currentChild.getKey();
+ JsonNode value = currentChild.getValue();
+ //if the entry's value has its own children, do a recursion.
+ //if the entry has no children, store the key and value.
+ //for we don't know the specific type of the entry's value, we
+ // should give it to a method which can handle JsonNode
+ if (value.isContainerNode()) {
+ walkJsonNode(jsonListener, key, value);
+ } else {
+ jsonListener.enterJsonNode(key, value);
+ jsonListener.exitJsonNode(value);
+ }
+ }
+ jsonListener.exitJsonNode(objectNode);
+ }
+
+ /**
+ * Walks the JSON data tree. This method is called when we don't know
+ * the exact type of a json node.
+ *
+ * @param jsonListener Json listener implemented by the user
+ * @param fieldName the original object node field
+ * @param rootNode the json node which needs to be walk
+ */
+ private void walkJsonNode(JsonListener jsonListener, String fieldName,
+ JsonNode rootNode) {
+ if (rootNode.isObject()) {
+ walk(jsonListener, fieldName, (ObjectNode) rootNode);
+ return;
+ }
+
+ if (rootNode.isArray()) {
+ walkArrayNode(jsonListener, fieldName, (ArrayNode) rootNode);
+ }
+ }
+
+ /**
+ * Walks the JSON data tree. This method is called when the user knows the
+ * json node type is ArrayNode.
+ *
+ * @param jsonListener Json listener implemented by the user
+ * @param fieldName the original object node field
+ * @param rootNode the json node which needs to be walk
+ */
+ private void walkArrayNode(JsonListener jsonListener, String fieldName,
+ ArrayNode rootNode) {
+ if (rootNode == null) {
+ return;
+ }
+ //enter the array node.
+ jsonListener.enterJsonNode(fieldName, rootNode);
+ Iterator<JsonNode> children = rootNode.elements();
+ while (children.hasNext()) {
+ JsonNode currentChild = children.next();
+ if (currentChild.isContainerNode()) {
+ walkJsonNode(jsonListener, null, currentChild);
+ }
+ }
+ jsonListener.exitJsonNode(rootNode);
+ }
+}
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
new file mode 100644
index 0000000..4a130f7
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/JsonToYdtListener.java
@@ -0,0 +1,163 @@
+/*
+ * 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.yms.ydt.YdtBuilder;
+import org.onosproject.yms.ydt.YdtContext;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.fasterxml.jackson.databind.node.JsonNodeType.ARRAY;
+import static com.google.common.base.Strings.isNullOrEmpty;
+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 Logger log = getLogger(getClass());
+
+ private YdtBuilder ydtBuilder;
+ private String defaultMultiInsNodeName;
+ private YdtContext rpcModule;
+
+ /**
+ * 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 (!isNullOrEmpty(defaultMultiInsNodeName)) {
+ ydtBuilder.addChild(defaultMultiInsNodeName, null,
+ MULTI_INSTANCE_NODE);
+ }
+ return;
+ }
+ JsonNodeType nodeType = node.getNodeType();
+ switch (nodeType) {
+ case OBJECT:
+ processObjectNode(fieldName);
+ break;
+
+ case ARRAY:
+ processArrayNode(fieldName, node);
+ break;
+
+ //TODO for now, just process the following three node type
+ case STRING:
+ case NUMBER:
+ case BOOLEAN:
+ ydtBuilder.addLeaf(fieldName, null, 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 (jsonNode.getNodeType() == ARRAY) {
+ return;
+ }
+ 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) {
+ 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;
+ 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(fieldName, null, sets);
+ } else {
+ this.defaultMultiInsNodeName = fieldName;
+ }
+ }
+}
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
new file mode 100644
index 0000000..fa8b133
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/ParserUtils.java
@@ -0,0 +1,259 @@
+/*
+ * 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.node.ObjectNode;
+import com.google.common.base.Splitter;
+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.yms.ydt.YdtBuilder;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ydt.YdtContextOperationType;
+import org.onosproject.yms.ydt.YdtListener;
+import org.onosproject.yms.ydt.YdtType;
+import org.onosproject.yms.ydt.YdtWalker;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.yms.ydt.YdtContextOperationType.NONE;
+
+/**
+ * Utils to complete the conversion between JSON and YDT(YANG DATA MODEL).
+ */
+public final class ParserUtils {
+
+ private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+ private static final Splitter COMMA_SPLITTER = Splitter.on(',');
+ private static final String EQUAL = "=";
+ private static final String COMMA = ",";
+ private static final String COLON = ":";
+ private static final String URI_ENCODING_CHAR_SET = "ISO-8859-1";
+ private static final String ERROR_LIST_MSG = "List/Leaf-list node should be " +
+ "in format \"nodeName=key\"or \"nodeName=instance-value\"";
+ private static final String ERROR_MODULE_MSG = "First node should be in " +
+ "format \"moduleName:nodeName\"";
+
+ // no instantiation
+ private ParserUtils() {
+ }
+
+ /**
+ * Converts URI identifier to YDT builder.
+ *
+ * @param id the uri identifier from web request
+ * @param builder the base ydt builder
+ * @param opType the ydt operation type for the uri
+ */
+ public static void convertUriToYdt(String id,
+ YdtBuilder builder,
+ YdtContextOperationType opType) {
+ checkNotNull(id, "uri identifier should not be null");
+ List<String> paths = urlPathArgsDecode(SLASH_SPLITTER.split(id));
+ if (!paths.isEmpty()) {
+ processPathSegments(paths, builder, opType);
+ }
+ }
+
+ /**
+ * Converts JSON objectNode to YDT builder. The objectNode can be any
+ * standard JSON node, node just for RESTconf payload.
+ *
+ * @param objectNode the objectNode from web request
+ * @param builder the base ydt builder
+ */
+ public static void convertJsonToYdt(ObjectNode objectNode,
+ YdtBuilder builder) {
+
+ JsonToYdtListener listener = new JsonToYdtListener(builder);
+ new DefaultJsonWalker().walk(listener, null, objectNode);
+ }
+
+ /**
+ * Converts a Ydt context tree to a JSON object.
+ *
+ * @param rootName the name of the YdtContext from which the YdtListener
+ * start to builder a Json Object
+ * @param context a abstract data model for YANG data
+ * @param walker abstraction of an entity which provides interfaces for
+ * YDT walk
+ * @return the JSON node corresponding the YANG data
+ */
+ public static ObjectNode convertYdtToJson(String rootName,
+ YdtContext context,
+ YdtWalker walker) {
+ JsonBuilder builder = new DefaultJsonBuilder();
+ YdtListener listener = new YdtToJsonListener(rootName, builder);
+ walker.walk(listener, context);
+ return builder.getTreeNode();
+ }
+
+ /**
+ * Converts a list of path segments to a YDT builder tree.
+ *
+ * @param paths the list of path segments split from URI
+ * @param builder the base YDT builder
+ * @param opType the YDT operation type for the Path segment
+ * @return the YDT builder with the tree info of paths
+ */
+ private static YdtBuilder processPathSegments(List<String> paths,
+ YdtBuilder builder,
+ YdtContextOperationType opType) {
+ if (paths.isEmpty()) {
+ return builder;
+ }
+ boolean isLastNode = paths.size() == 1;
+ YdtContextOperationType opTypeForThisNode = isLastNode ? opType : NONE;
+
+ String path = paths.iterator().next();
+ if (path.contains(COLON)) {
+ addModule(builder, path);
+ addNode(path, builder, opTypeForThisNode);
+ } else if (path.contains(EQUAL)) {
+ addListOrLeafList(path, builder, opTypeForThisNode);
+ } else {
+ addLeaf(path, builder, opTypeForThisNode);
+ }
+
+ if (isLastNode) {
+ return builder;
+ }
+ List<String> remainPaths = paths.subList(1, paths.size());
+ processPathSegments(remainPaths, builder, opType);
+
+ 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) {
+ String nodeName = getPreSegment(path, EQUAL);
+ String keyStr = getLatterSegment(path, EQUAL);
+ if (keyStr == null) {
+ throw new JsonParseException(ERROR_LIST_MSG);
+ }
+ builder.setDefaultEditOperationType(opType);
+ if (keyStr.contains(COMMA)) {
+ List<String> keys = Lists.
+ newArrayList(COMMA_SPLITTER.split(keyStr));
+ builder.addMultiInstanceChild(nodeName, null, keys);
+ } else {
+ builder.addMultiInstanceChild(nodeName, null,
+ Lists.newArrayList(keyStr));
+ }
+ return builder;
+ }
+
+ private static YdtBuilder addLeaf(String path, YdtBuilder builder,
+ YdtContextOperationType opType) {
+ checkNotNull(path);
+ builder.addChild(path, null, opType);
+ return builder;
+ }
+
+ /**
+ * Returns the previous segment of a path which is separated by a split char.
+ * For example:
+ * <pre>
+ * "foo:bar", ":" --> "foo"
+ * </pre>
+ *
+ * @param path the original path string
+ * @param splitChar char used to split the path
+ * @return the previous segment of the path
+ */
+ private static String getPreSegment(String path, String splitChar) {
+ int idx = path.indexOf(splitChar);
+ if (idx == -1) {
+ return null;
+ }
+
+ if (path.indexOf(splitChar, idx + 1) != -1) {
+ return null;
+ }
+
+ return path.substring(0, idx);
+ }
+
+ /**
+ * Returns the latter segment of a path which is separated by a split char.
+ * For example:
+ * <pre>
+ * "foo:bar", ":" --> "bar"
+ * </pre>
+ *
+ * @param path the original path string
+ * @param splitChar char used to split the path
+ * @return the latter segment of the path
+ */
+ private static String getLatterSegment(String path, String splitChar) {
+ int idx = path.indexOf(splitChar);
+ if (idx == -1) {
+ return path;
+ }
+
+ if (path.indexOf(splitChar, idx + 1) != -1) {
+ return null;
+ }
+
+ return path.substring(idx + 1);
+ }
+
+ /**
+ * Converts a list of path from the original format to ISO-8859-1 code.
+ *
+ * @param paths the original paths
+ * @return list of decoded paths
+ */
+ public static List<String> urlPathArgsDecode(Iterable<String> paths) {
+ try {
+ List<String> decodedPathArgs = new ArrayList<>();
+ for (String pathArg : paths) {
+ String decode = URLDecoder.decode(pathArg,
+ URI_ENCODING_CHAR_SET);
+ decodedPathArgs.add(decode);
+ }
+ return decodedPathArgs;
+ } catch (UnsupportedEncodingException e) {
+ throw new JsonParseException("Invalid URL path arg '" +
+ paths + "': ", e);
+ }
+ }
+}
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/YdtToJsonListener.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/YdtToJsonListener.java
new file mode 100644
index 0000000..b0ce26b
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/YdtToJsonListener.java
@@ -0,0 +1,127 @@
+/*
+ * 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.node.JsonNodeType;
+import org.onosproject.protocol.restconf.server.utils.exceptions.YdtParseException;
+import org.onosproject.protocol.restconf.server.utils.parser.api.JsonBuilder;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ydt.YdtListener;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Represents implementation of codec YDT listener.
+ */
+public class YdtToJsonListener implements YdtListener {
+
+ private static final String EMPTY = "";
+ private JsonBuilder jsonBuilder;
+ //the root name of the json
+ //the input YdtContext is usually a total tree of a YANG resource
+ //this property is used to mark the start of the request node.
+ private String rootName;
+ //the parse state
+ private boolean isBegin;
+
+ /**
+ * Creates a listener for the process of a Ydt, the listener will try to
+ * transfer the Ydt to a JSON Object.
+ *
+ * @param rootName the name of a specific YdtContext begin to process
+ * @param jsonBuilder the JSON builder to build a JSON object
+ */
+ public YdtToJsonListener(String rootName, JsonBuilder jsonBuilder) {
+ this.jsonBuilder = jsonBuilder;
+ this.rootName = rootName;
+ this.isBegin = isNullOrEmpty(rootName);
+ }
+
+ @Override
+ public void enterYdtNode(YdtContext ydtContext) {
+ String name = ydtContext.getName();
+
+ if (!isBegin && name.equals(rootName)) {
+ isBegin = true;
+ }
+ if (!isBegin) {
+ return;
+ }
+
+ switch (ydtContext.getYdtType()) {
+
+ case SINGLE_INSTANCE_NODE:
+ jsonBuilder.addNodeTopHalf(name, JsonNodeType.OBJECT);
+ break;
+ case MULTI_INSTANCE_NODE:
+ YdtContext preNode = ydtContext.getPreviousSibling();
+ if (preNode == null || !preNode.getName().equals(name)) {
+ jsonBuilder.addNodeTopHalf(name, JsonNodeType.ARRAY);
+ }
+ jsonBuilder.addNodeTopHalf(EMPTY, JsonNodeType.OBJECT);
+ break;
+ case SINGLE_INSTANCE_LEAF_VALUE_NODE:
+ jsonBuilder.addNodeWithValueTopHalf(name, ydtContext.getValue());
+ break;
+ case MULTI_INSTANCE_LEAF_VALUE_NODE:
+ jsonBuilder.addNodeWithSetTopHalf(name, ydtContext.getValueSet());
+ break;
+ default:
+ throw new YdtParseException("unknown Ydt type " +
+ ydtContext.getYdtType());
+ }
+
+ }
+
+ @Override
+ public void exitYdtNode(YdtContext ydtContext) {
+
+ if (!isBegin) {
+ return;
+ }
+
+ String curName = ydtContext.getName();
+ YdtContext nextNode = ydtContext.getNextSibling();
+ switch (ydtContext.getYdtType()) {
+
+ case SINGLE_INSTANCE_NODE:
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.OBJECT);
+ break;
+ case MULTI_INSTANCE_NODE:
+ if (nextNode == null || !nextNode.getName().equals(curName)) {
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.OBJECT);
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.ARRAY);
+ } else {
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.OBJECT);
+ }
+ break;
+ case SINGLE_INSTANCE_LEAF_VALUE_NODE:
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.STRING);
+ break;
+ case MULTI_INSTANCE_LEAF_VALUE_NODE:
+ jsonBuilder.addNodeBottomHalf(JsonNodeType.ARRAY);
+ break;
+ default:
+ throw new YdtParseException("Unknown Ydt type " +
+ ydtContext.getYdtType());
+ }
+ if (curName.equals(rootName) &&
+ (nextNode == null || !nextNode.getName().equals(rootName))) {
+ isBegin = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/package-info.java b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/package-info.java
new file mode 100644
index 0000000..3e3c49b
--- /dev/null
+++ b/protocols/restconf/server/utils/src/main/java/org/onosproject/protocol/restconf/server/utils/parser/json/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provider utilities to support the data format based encoding and decoding,
+ * used by YMSC to operate on different data format and YDT(YANG DATA TYPE).
+ */
+
+package org.onosproject.protocol.restconf.server.utils.parser.json;
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/test/java/org/onosproject/restconf/utils/parser/json/DefaultJsonWalkerTest.java b/protocols/restconf/server/utils/src/test/java/org/onosproject/restconf/utils/parser/json/DefaultJsonWalkerTest.java
new file mode 100644
index 0000000..c82f0f8
--- /dev/null
+++ b/protocols/restconf/server/utils/src/test/java/org/onosproject/restconf/utils/parser/json/DefaultJsonWalkerTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.restconf.utils.parser.json;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.protocol.restconf.server.utils.parser.api.JsonListener;
+import org.onosproject.protocol.restconf.server.utils.parser.json.DefaultJsonWalker;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+public class DefaultJsonWalkerTest {
+
+ private static final String[] EXP_TEXT_ARRAY = {
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is name",
+ "Exit: type is STRING",
+ "Enter: type is STRING name is surname",
+ "Exit: type is STRING",
+ "Exit: type is OBJECT"
+ };
+
+ private static final String[] EXP_NODE_LIST_ARRAY = {
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is surname",
+ "Exit: type is STRING",
+ "Enter: type is ARRAY name is networklist",
+ "Exit: type is ARRAY",
+ "Exit: type is OBJECT"
+ };
+
+ private static final String[] EXP_NODE_WITH_ARRAY = {
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is surname",
+ "Exit: type is STRING",
+ "Enter: type is ARRAY name is networklist",
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is network-id",
+ "Exit: type is STRING",
+ "Enter: type is STRING name is server-provided",
+ "Exit: type is STRING",
+ "Exit: type is OBJECT",
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is network-id",
+ "Exit: type is STRING",
+ "Enter: type is STRING name is server-provided",
+ "Exit: type is STRING",
+ "Exit: type is OBJECT",
+ "Enter: type is OBJECT name is null",
+ "Enter: type is STRING name is network-id",
+ "Exit: type is STRING",
+ "Enter: type is STRING name is server-provided",
+ "Exit: type is STRING",
+ "Exit: type is OBJECT",
+ "Exit: type is ARRAY",
+ "Exit: type is OBJECT"
+ };
+ private static final String WRONG_CONTENT_MSG = "Wrong content in array";
+
+ private final List<String> logger = new ArrayList<>();
+
+ DefaultJsonWalker defaultJsonWalker = new DefaultJsonWalker();
+ InternalJsonListener jsonListener = new InternalJsonListener();
+
+ ObjectNode arrayNode;
+ ObjectNode textNode;
+ ObjectNode listNode;
+
+ @Before
+ public void setup() throws Exception {
+ textNode = loadJsonFile("/textNode.json");
+ listNode = loadJsonFile("/listNode.json");
+ arrayNode = loadJsonFile("/arrayNode.json");
+ }
+
+ private ObjectNode loadJsonFile(String path) throws Exception {
+ InputStream jsonStream = getClass().getResourceAsStream(path);
+ ObjectMapper mapper = new ObjectMapper();
+ return (ObjectNode) mapper.readTree(jsonStream);
+ }
+
+ private void assertWalkResult(String[] expectArray, List<String> logger) {
+ for (int i = 0; i < expectArray.length; i++) {
+ assertThat(WRONG_CONTENT_MSG,
+ true,
+ is(logger.get(i).contentEquals(expectArray[i])));
+ }
+ }
+
+ @Test
+ public void testWalkTextNode() throws Exception {
+
+ defaultJsonWalker.walk(jsonListener, null, textNode);
+ assertWalkResult(EXP_TEXT_ARRAY, logger);
+ }
+
+ @Test
+ public void testWalkNodeWithList() throws Exception {
+ defaultJsonWalker.walk(jsonListener, null, listNode);
+ assertWalkResult(EXP_NODE_LIST_ARRAY, logger);
+ }
+
+ @Test
+ public void testWalkNodeWithArray() throws Exception {
+ defaultJsonWalker.walk(jsonListener, null, arrayNode);
+ assertWalkResult(EXP_NODE_WITH_ARRAY, logger);
+ }
+
+ private class InternalJsonListener implements JsonListener {
+
+ @Override
+ public void enterJsonNode(String fieldName, JsonNode node) {
+ logger.add("Enter: type is " + node.getNodeType() + " name is " +
+ fieldName);
+ }
+
+ @Override
+ public void exitJsonNode(JsonNode node) {
+ logger.add("Exit: type is " + node.getNodeType());
+ }
+ }
+}
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/test/resources/arrayNode.json b/protocols/restconf/server/utils/src/test/resources/arrayNode.json
new file mode 100644
index 0000000..2035e82
--- /dev/null
+++ b/protocols/restconf/server/utils/src/test/resources/arrayNode.json
@@ -0,0 +1,18 @@
+{
+ "surname": "Bangalore",
+ "networklist":[
+ {
+ "network-id": "520",
+ "server-provided": "123"
+ },
+ {
+ "network-id": "521",
+ "server-provided": "124"
+ },
+ {
+ "network-id": "523",
+ "server-provided": "125"
+ }
+
+ ]
+}
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/test/resources/listNode.json b/protocols/restconf/server/utils/src/test/resources/listNode.json
new file mode 100644
index 0000000..c7902f5
--- /dev/null
+++ b/protocols/restconf/server/utils/src/test/resources/listNode.json
@@ -0,0 +1,8 @@
+{
+ "surname": "Bangalore",
+ "networklist":[
+ "0.79",
+ "1.04",
+ "3.14"
+ ]
+}
\ No newline at end of file
diff --git a/protocols/restconf/server/utils/src/test/resources/textNode.json b/protocols/restconf/server/utils/src/test/resources/textNode.json
new file mode 100644
index 0000000..8894cfb
--- /dev/null
+++ b/protocols/restconf/server/utils/src/test/resources/textNode.json
@@ -0,0 +1,4 @@
+{
+ "name": "Huawei",
+ "surname": "Bangalore"
+}
\ No newline at end of file