JSON serializer fixes

* Removed redundant module name prefixes to comply with RFC 7951
* Added the top level JSON node, which was missing from RESTCONF's GET output

Change-Id: If8a022571b449b802750fb9f613d71c1e1db6262
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java
index 617f871..64120c1 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java
@@ -40,7 +40,7 @@
     /**
      * Creates an instance of data node JSON visitor.
      *
-     * @param jb json builder
+     * @param jb      json builder
      * @param context yang serializer context
      */
     public DataNodeJsonVisitor(JsonBuilder jb, YangSerializerContext context) {
@@ -51,7 +51,7 @@
     @Override
     public void enterDataNode(DataNode dataNode,
                               DataNodeSiblingPositionType siblingType) {
-        String nodeName = getNodeNameWithModuleName(dataNode.key().schemaId());
+        String nodeName = getNodeName(dataNode);
         switch (dataNode.type()) {
             case SINGLE_INSTANCE_NODE:
                 jsonBuilder.addNodeTopHalf(nodeName, JsonNodeType.OBJECT);
@@ -79,17 +79,22 @@
             default:
                 break;
         }
+        jsonBuilder.pushModuleName(getModuleNameFromDataNode(dataNode));
     }
 
-    private String getNodeNameWithModuleName(SchemaId schemaId) {
+    private String getModuleNameFromDataNode(DataNode dataNode) {
+        String nameSpace = dataNode.key().schemaId().namespace();
+        return getModuleNameFromNameSpace(jsonSerializerContext, nameSpace);
+    }
+
+    private String getNodeName(DataNode dataNode) {
+        SchemaId schemaId = dataNode.key().schemaId();
         String nodeName = schemaId.name();
-        String nameSpace = schemaId.namespace();
-        String moduleName = getModuleNameFromNameSpace(jsonSerializerContext,
-                                                       nameSpace);
+        String moduleName = getModuleNameFromDataNode(dataNode);
 
         StringBuilder builder = new StringBuilder();
 
-        if (nameSpace != null) {
+        if (moduleName != null && !moduleName.equals(jsonBuilder.subTreeModuleName())) {
             builder.append(moduleName);
             builder.append(COLON);
         }
@@ -126,5 +131,6 @@
             default:
                 break;
         }
+        jsonBuilder.popModuleName();
     }
 }
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
index 3dc0ff5..9492a15 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
@@ -25,6 +25,7 @@
 
 import java.io.IOException;
 import java.util.Set;
+import java.util.Stack;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Strings.isNullOrEmpty;
@@ -42,15 +43,19 @@
     private static final String COMMA = ",";
     private static final String COLON = ":";
     private static final String QUOTE = "\"";
+    private static final String ROOT_MODULE_NAME = "ROOT";
 
+    private Stack<String> moduleNameStack;
 
     public DefaultJsonBuilder(String rootName) {
         checkNotNull(rootName);
-        this.treeString = new StringBuilder(rootName);
+        treeString = new StringBuilder(rootName);
+        moduleNameStack = new Stack<>();
     }
 
     public DefaultJsonBuilder() {
-        this.treeString = new StringBuilder();
+        treeString = new StringBuilder();
+        moduleNameStack = new Stack<>();
     }
 
     @Override
@@ -141,8 +146,6 @@
 
     @Override
     public String getTreeString() {
-        removeCommaIfExist();
-        removeFirstFieldNameIfExist();
         return treeString.toString();
     }
 
@@ -178,8 +181,34 @@
     }
 
     @Override
-    public void removeExtraTerminator() {
+    public String subTreeModuleName() {
+        return moduleNameStack.peek();
+    }
+
+    @Override
+    public void pushModuleName(String moduleName) {
+        moduleNameStack.push(moduleName);
+    }
+
+    @Override
+    public void popModuleName() {
+        moduleNameStack.pop();
+    }
+
+    @Override
+    public void initializeJson() {
+        if (!moduleNameStack.empty()) {
+            moduleNameStack.removeAllElements();
+        }
+        moduleNameStack.push(ROOT_MODULE_NAME);
+        treeString.setLength(0);
+        treeString.append(LEFT_BRACE);
+    }
+
+    @Override
+    public void finalizeJson() {
         removeCommaIfExist();
+        treeString.append(RIGHT_BRACE);
     }
 
     private void appendField(String fieldName) {
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
index 2f9ca39..e78bf3e 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
@@ -59,12 +59,13 @@
         checkNotNull(dataNode, "data node cannot be null");
 
         JsonBuilder jsonBuilder = new DefaultJsonBuilder();
+        jsonBuilder.initializeJson();
         DataNodeVisitor treeNodeListener = new DataNodeJsonVisitor(jsonBuilder, context);
 
         DataNodeSiblingPositionType siblingType = NOT_MULTI_INSTANCE_NODE;
         walkDataNodeTree(treeNodeListener, dataNode, siblingType);
 
-        jsonBuilder.removeExtraTerminator();
+        jsonBuilder.finalizeJson();
         ObjectNode resultData = jsonBuilder.getTreeNode();
         return resultData;
     }
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
index cb53cdd..aff22db 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
@@ -88,5 +88,43 @@
      */
     ObjectNode getTreeNode();
 
-    void removeExtraTerminator();
+    /**
+     * Returns the YANG module name of the JSON subtree that the builder
+     * is currently building. The YANG module name represents the name
+     * space of the subtree.
+     *
+     * @return YANG module name
+     */
+    String subTreeModuleName();
+
+    /**
+     * Updates the YANG module name of the JSON subtree that the builder
+     * is currently building. The YANG module name represents the name
+     * space of the subtree. This function may be called when the builder
+     * starts to build a data node.
+     *
+     * @param moduleName YANG module name of the current subtree
+     */
+    void pushModuleName(String moduleName);
+
+    /**
+     * Removes the YANG module name of the JSON subtree that the builder
+     * is currently building. This function may be called when the builder
+     * finishes building a data node.
+     */
+    void popModuleName();
+
+    /**
+     * Initializes the output JSON and emits the JSON starting symbol
+     * (e.g., the left curly bracket). This method should be the first method
+     * to be called when a JSON building process starts.
+     */
+    void initializeJson();
+
+    /**
+     * Finalizes the output JSON and emits the JSON terminating symbol
+     * (e.g., the right curly bracket). This method should be the last method
+     * to be called when a JSON building process finishes.
+     */
+    void finalizeJson();
 }