Adding 'cleanjson' output format, along with implementation of lists.

Also includes test-framework update to allow testing of cleanjson.

Change-Id: I5c37d3b5aad7f286eba1cb8cb5f05ad456a6521c
Reviewed-on: https://asterix-gerrit.ics.uci.edu/361
Reviewed-by: Ian Maxon <imaxon@apache.org>
Tested-by: Ian Maxon <imaxon@apache.org>
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java b/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
index db6d041..3a33bbe 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
@@ -324,8 +324,8 @@
         builder.setPredicateEvaluatorFactoryProvider(format.getPredicateEvaluatorFactoryProvider());
 
         switch (conf.fmt()) {
-            case JSON:
-                builder.setPrinterProvider(format.getJSONPrinterFactoryProvider());
+            case LOSSLESS_JSON:
+                builder.setPrinterProvider(format.getLosslessJSONPrinterFactoryProvider());
                 break;
             case CSV:
                 builder.setPrinterProvider(format.getCSVPrinterFactoryProvider());
@@ -333,6 +333,9 @@
             case ADM:
                 builder.setPrinterProvider(format.getADMPrinterFactoryProvider());
                 break;
+            case CLEAN_JSON:
+                builder.setPrinterProvider(format.getCleanJSONPrinterFactoryProvider());
+                break;
             default:
                 throw new RuntimeException("Unexpected OutputFormat!");
         }
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 17752a3..4e64802 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
@@ -32,7 +32,7 @@
  * <li> It also allows you to request additional output for optional
  * out-of-band data about the execution (query plan, etc).
  * <li> It allows you to specify the output format for the primary
- * execution output - JSON, CSV, etc.
+ * execution output - LOSSLESS_JSON, CSV, etc.
  * <li> It allows you to specify output format-specific parameters.
  */
 
@@ -42,8 +42,9 @@
      */
     public enum OutputFormat {
         ADM,
-        JSON,
-        CSV
+        CSV,
+        CLEAN_JSON,
+        LOSSLESS_JSON
     };
 
     /**
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
index 35d4c37..99706ed 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/APIServlet.java
@@ -69,9 +69,11 @@
         } else if (output.equals("CSV-Header")) {
             format = OutputFormat.CSV;
             csv_and_header = true;
+        } else if (output.equals("LOSSLESS_JSON")) {
+            format = OutputFormat.LOSSLESS_JSON;
         } else {
             // Default output format
-            format = OutputFormat.JSON;
+            format = OutputFormat.CLEAN_JSON;
         }
 
         String query = request.getParameter("query");
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ConnectorAPIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ConnectorAPIServlet.java
index 1091a29..b213bca 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ConnectorAPIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ConnectorAPIServlet.java
@@ -46,7 +46,7 @@
 
 /***
  * The REST API that takes a dataverse name and a dataset name as the input
- * and returns an array of file splits (IP, file-path) of the dataset in JSON.
+ * and returns an array of file splits (IP, file-path) of the dataset in LOSSLESS_JSON.
  * It is mostly used by external runtime, e.g., Pregelix or IMRU to pull data
  * in parallel from existing AsterixDB datasets.
  *
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryStatusAPIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryStatusAPIServlet.java
index 4a49dd7..2751945 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryStatusAPIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/QueryStatusAPIServlet.java
@@ -68,7 +68,7 @@
             JobId jobId = new JobId(handle.getLong(0));
             ResultSetId rsId = new ResultSetId(handle.getLong(1));
 
-            /* TODO(madhusudancs): We need to find a way to JSON serialize default format obtained from
+            /* TODO(madhusudancs): We need to find a way to LOSSLESS_JSON serialize default format obtained from
              * metadataProvider in the AQLTranslator and store it as part of the result handle.
              */
             ResultReader resultReader = new ResultReader(hcc, hds);
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
index 314f0e0..7db0c94 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/RESTAPIServlet.java
@@ -66,9 +66,9 @@
         throws IOException {
         response.setCharacterEncoding("utf-8");
 
-        // JSON output is the default; most generally useful for a
+        // CLEAN_JSON output is the default; most generally useful for a
         // programmatic HTTP API
-        OutputFormat format = OutputFormat.JSON;
+        OutputFormat format = OutputFormat.CLEAN_JSON;
 
         // First check the "output" servlet parameter.
         String output = request.getParameter("output");
@@ -92,6 +92,13 @@
             }
         }
 
+        // If it's JSON, check for the "lossless" flag
+        if (format == OutputFormat.CLEAN_JSON &&
+                ("true".equals(request.getParameter("lossless")) ||
+                (accept != null && accept.contains("lossless=true")))) {
+            format = OutputFormat.LOSSLESS_JSON;
+        }
+
         SessionConfig sessionConfig = new SessionConfig(response.getWriter(), format);
 
         // Now that format is set, output the content-type
@@ -99,7 +106,9 @@
             case ADM:
                 response.setContentType("application/x-adm");
                 break;
-            case JSON:
+            case CLEAN_JSON:
+                // No need to reflect "clean-ness" in output type; fall through
+            case LOSSLESS_JSON:
                 response.setContentType("application/json");
                 break;
             case CSV: {
diff --git a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ShutdownAPIServlet.java b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ShutdownAPIServlet.java
index dcfdd97..f5b5cbb 100644
--- a/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ShutdownAPIServlet.java
+++ b/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/ShutdownAPIServlet.java
@@ -52,12 +52,12 @@
         response.setCharacterEncoding("utf-8");
 
         PrintWriter out = response.getWriter();
-        OutputFormat format = OutputFormat.JSON;
+        OutputFormat format = OutputFormat.LOSSLESS_JSON;
         String accept = request.getHeader("Accept");
         if ((accept == null) || (accept.contains("application/x-adm"))) {
             format = OutputFormat.ADM;
         } else if (accept.contains("application/json")) {
-            format = OutputFormat.JSON;
+            format = OutputFormat.LOSSLESS_JSON;
         }
         StringWriter sw = new StringWriter();
         IOUtils.copy(request.getInputStream(), sw, StandardCharsets.UTF_8.name());
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 9b81ded..44c878d 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
@@ -117,9 +117,10 @@
             case CSV:
                 need_commas = false;
                 break;
-            case JSON:
+            case LOSSLESS_JSON:
+            case CLEAN_JSON:
             case ADM:
-                // Conveniently, JSON and ADM have the same syntax for an
+                // Conveniently, LOSSLESS_JSON and ADM have the same syntax for an
                 // "ordered list", and our representation of the result of a
                 // statement is an ordered list of instances.
                 conf.out().print("[ ");
@@ -167,7 +168,8 @@
         conf.out().flush();
 
         switch (conf.fmt()) {
-            case JSON:
+            case LOSSLESS_JSON:
+            case CLEAN_JSON:
             case ADM:
                 conf.out().println(" ]");
                 break;
diff --git a/asterix-app/src/main/resources/webui/querytemplate.html b/asterix-app/src/main/resources/webui/querytemplate.html
index 9088251..8308a61 100644
--- a/asterix-app/src/main/resources/webui/querytemplate.html
+++ b/asterix-app/src/main/resources/webui/querytemplate.html
@@ -77,7 +77,7 @@
             var errorPattern = /<div class="accordion" id="errorblock">/g;
             var sectionsSeparator = '<h4>';
             var resultPat = 'Results:</h4>';
-            
+
             if (errorPattern.test(data)) {
                 $('#output-heading').html('Error');
                 $('#output-heading').addClass('error');
@@ -210,7 +210,7 @@
               <label class="query">Query</label>
               <textarea rows="10" id="qry" name="query" class="query" value="%s" placeholder="Type your AQL query ..."></textarea>
             </div>
-            
+
             <div class="btn-group">
               <button id="checkboxes-on" class="btn">
                   <i id="opts" class="icon-ok" style="display:none;"></i>Select Options</button>
@@ -225,7 +225,8 @@
                   <option selected value="ADM">ADM</option>
                   <option value="CSV">CSV (no header)</option>
                   <option value="CSV-Header">CSV (with header)</option>
-                  <option value="JSON">JSON</option>
+                  <option value="CLEAN_JSON">JSON</option>
+                  <option value="LOSSLESS_JSON">JSON (lossless)</option>
                 </select>
               </label>
               <label class="checkbox optlabel"><input type="checkbox" name="print-expr-tree" value="true" /> Print parsed expressions</label>
@@ -260,4 +261,3 @@
   </div>
 </body>
 </html>
-