add parameter to QueryServiceServlet to indent JSON

Change-Id: Id197d3ad6aa17c9a36bb3845bd3ca75a695ba6d9
Reviewed-on: https://asterix-gerrit.ics.uci.edu/750
Reviewed-by: Yingyi Bu <buyingyi@gmail.com>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java b/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
index 2ed67b2..7bfc55c 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/common/SessionConfig.java
@@ -92,6 +92,11 @@
      */
     public static final String FORMAT_WRAPPER_ARRAY = "format-wrapper-array";
 
+    /**
+     * Format flag: indent JSON results.
+     */
+    public static final String INDENT_JSON = "indent-json";
+
     public interface ResultDecorator {
         PrintWriter print(PrintWriter pw);
     }
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/JSONUtil.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/JSONUtil.java
index 56f349c..d69c3c1 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/JSONUtil.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/JSONUtil.java
@@ -26,13 +26,17 @@
 
 public class JSONUtil {
 
-    static final String INDENT = "    ";
+    static final String INDENT = "\t";
 
     public static String indent(String str) {
+        return indent(str, 0);
+    }
+
+    public static String indent(String str, int initialIndent) {
         try {
-            return append(new StringBuilder(), new JSONObject(str), 0).toString();
+            return append(new StringBuilder(), new JSONObject(str), initialIndent).toString();
         } catch (JSONException e) {
-            throw new IllegalArgumentException(e);
+            return str;
         }
     }
 
@@ -43,7 +47,7 @@
             return append(sb, (JSONArray) o, indent);
         } else if (o instanceof String) {
             return quote(sb, (String) o);
-        } else if (o instanceof Number || o instanceof Boolean) {
+        } else if (JSONObject.NULL.equals(o) || o instanceof Number || o instanceof Boolean) {
             return sb.append(String.valueOf(o));
         }
         throw new UnsupportedOperationException(o.getClass().getSimpleName());
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryServiceServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryServiceServlet.java
index c4d270b..4376b22 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryServiceServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryServiceServlet.java
@@ -63,7 +63,8 @@
         statement,
         format,
         // Asterix
-        header
+        header,
+        indent
     }
 
     public enum Header {
@@ -159,14 +160,16 @@
         SessionConfig.ResultDecorator resultPostfix = new SessionConfig.ResultDecorator() {
             @Override
             public PrintWriter print(PrintWriter pw) {
-                pw.print(",\n");
+                pw.print("\t,\n");
                 return pw;
             }
         };
 
         SessionConfig.OutputFormat format = getFormat(request);
         SessionConfig sessionConfig = new SessionConfig(resultWriter, format, resultPrefix, resultPostfix);
-        sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, (format == SessionConfig.OutputFormat.CLEAN_JSON));
+        sessionConfig.set(SessionConfig.FORMAT_WRAPPER_ARRAY, format == SessionConfig.OutputFormat.CLEAN_JSON);
+        boolean indentJson = Boolean.parseBoolean(request.getParameter(Parameter.indent.name()));
+        sessionConfig.set(SessionConfig.INDENT_JSON, indentJson);
 
         if (format == SessionConfig.OutputFormat.CSV && ("present".equals(request.getParameter(Parameter.header.name()))
                 || request.getHeader(Header.Accept.str()).contains("header=present"))) {
diff --git a/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java b/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
index f1d20d0..2fe7f28 100644
--- a/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
+++ b/asterix-app/src/main/java/org/apache/asterix/result/ResultUtils.java
@@ -33,6 +33,7 @@
 import org.apache.asterix.api.common.SessionConfig;
 import org.apache.asterix.api.common.SessionConfig.OutputFormat;
 import org.apache.asterix.api.http.servlet.APIServlet;
+import org.apache.asterix.api.http.servlet.JSONUtil;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.http.ParseException;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -135,6 +136,7 @@
                 break;
         }
 
+        final boolean indentJSON = conf.is(SessionConfig.INDENT_JSON);
         if (bytesRead > 0) {
             do {
                 try {
@@ -157,6 +159,10 @@
                             conf.out().print(", ");
                         }
                         notfirst = true;
+                        if (indentJSON) {
+                            // TODO(tillw): this is inefficient - do this during result generation
+                            result = JSONUtil.indent(result, 2);
+                        }
                         conf.out().print(result);
                         if (conf.fmt() == OutputFormat.CSV) {
                             conf.out().print("\r\n");