Add JSON pointable printers for pointables like list and record types.

git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_stabilization_result_distribution@1233 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/AListPrinter.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/AListPrinter.java
new file mode 100644
index 0000000..e0b3167
--- /dev/null
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/AListPrinter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * 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 from
+ * 
+ *     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 edu.uci.ics.asterix.om.pointables.printer.json;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.List;
+
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.om.pointables.AListPointable;
+import edu.uci.ics.asterix.om.pointables.base.IVisitablePointable;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.EnumDeserializer;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+
+/**
+ * This class is to print the content of a list. It is ONLY visible to
+ * APrintVisitor.
+ */
+class AListPrinter {
+    private static String BEGIN = "{ unorderedlist: [";
+    private static String BEGIN_ORDERED = "{ orderedlist: [";
+    private static String END = " ]}";
+    private static String COMMA = ", ";
+
+    private final Pair<PrintStream, ATypeTag> itemVisitorArg = new Pair<PrintStream, ATypeTag>(null, null);
+    private String begin = BEGIN;
+
+    public AListPrinter(boolean ordered) {
+        if (ordered) {
+            begin = BEGIN_ORDERED;
+        }
+    }
+
+    public void printList(AListPointable listAccessor, PrintStream ps, APrintVisitor visitor) throws IOException,
+            AsterixException {
+        List<IVisitablePointable> itemTags = listAccessor.getItemTags();
+        List<IVisitablePointable> items = listAccessor.getItems();
+        itemVisitorArg.first = ps;
+
+        // print the beginning part
+        ps.print(begin);
+
+        // print item 0 to n-2
+        for (int i = 0; i < items.size() - 1; i++) {
+            printItem(visitor, itemTags, items, i);
+            // print the comma
+            ps.print(COMMA);
+        }
+
+        // print item n-1
+        if (items.size() > 0) {
+            printItem(visitor, itemTags, items, items.size() - 1);
+        }
+
+        // print the end part
+        ps.print(END);
+    }
+
+    private void printItem(APrintVisitor visitor, List<IVisitablePointable> itemTags, List<IVisitablePointable> items,
+            int i) throws AsterixException {
+        IVisitablePointable itemTypeTag = itemTags.get(i);
+        IVisitablePointable item = items.get(i);
+        ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(itemTypeTag.getByteArray()[itemTypeTag
+                .getStartOffset()]);
+        itemVisitorArg.second = item.getLength() <= 1 ? ATypeTag.NULL : typeTag;
+        item.accept(visitor, itemVisitorArg);
+    }
+}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/APrintVisitor.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/APrintVisitor.java
new file mode 100644
index 0000000..b2d5339
--- /dev/null
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/APrintVisitor.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * 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 from
+ * 
+ *     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 edu.uci.ics.asterix.om.pointables.printer.json;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ABooleanPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ACirclePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ADatePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ADateTimePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ADoublePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ADurationPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AFloatPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AInt16Printer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AInt32Printer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AInt64Printer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AInt8Printer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ALinePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ANullPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.APoint3DPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.APointPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.APolygonPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ARectanglePrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.AStringPrinter;
+import edu.uci.ics.asterix.dataflow.data.nontagged.printers.json.ATimePrinter;
+import edu.uci.ics.asterix.om.pointables.AFlatValuePointable;
+import edu.uci.ics.asterix.om.pointables.AListPointable;
+import edu.uci.ics.asterix.om.pointables.ARecordPointable;
+import edu.uci.ics.asterix.om.pointables.base.IVisitablePointable;
+import edu.uci.ics.asterix.om.pointables.visitor.IVisitablePointableVisitor;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.NotImplementedException;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+
+/**
+ * This class is a IVisitablePointableVisitor implementation which recursively
+ * visit a given record, list or flat value of a given type, and print it to a
+ * PrintStream in adm format.
+ */
+public class APrintVisitor implements IVisitablePointableVisitor<Void, Pair<PrintStream, ATypeTag>> {
+
+    private final Map<IVisitablePointable, ARecordPrinter> raccessorToPrinter = new HashMap<IVisitablePointable, ARecordPrinter>();
+    private final Map<IVisitablePointable, AListPrinter> laccessorToPrinter = new HashMap<IVisitablePointable, AListPrinter>();
+
+    @Override
+    public Void visit(AListPointable accessor, Pair<PrintStream, ATypeTag> arg) throws AsterixException {
+        AListPrinter printer = laccessorToPrinter.get(accessor);
+        if (printer == null) {
+            printer = new AListPrinter(accessor.ordered());
+            laccessorToPrinter.put(accessor, printer);
+        }
+        try {
+            printer.printList(accessor, arg.first, this);
+        } catch (Exception e) {
+            throw new AsterixException(e);
+        }
+        return null;
+    }
+
+    @Override
+    public Void visit(ARecordPointable accessor, Pair<PrintStream, ATypeTag> arg) throws AsterixException {
+        ARecordPrinter printer = raccessorToPrinter.get(accessor);
+        if (printer == null) {
+            printer = new ARecordPrinter();
+            raccessorToPrinter.put(accessor, printer);
+        }
+        try {
+            printer.printRecord(accessor, arg.first, this);
+        } catch (Exception e) {
+            throw new AsterixException(e);
+        }
+        return null;
+    }
+
+    @Override
+    public Void visit(AFlatValuePointable accessor, Pair<PrintStream, ATypeTag> arg) {
+        try {
+            byte[] b = accessor.getByteArray();
+            int s = accessor.getStartOffset();
+            int l = accessor.getLength();
+            PrintStream ps = arg.first;
+            ATypeTag typeTag = arg.second;
+            switch (typeTag) {
+                case INT8: {
+                    AInt8Printer.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case INT16: {
+                    AInt16Printer.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case INT32: {
+                    AInt32Printer.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case INT64: {
+                    AInt64Printer.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case NULL: {
+                    ANullPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case BOOLEAN: {
+                    ABooleanPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case FLOAT: {
+                    AFloatPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case DOUBLE: {
+                    ADoublePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case DATE: {
+                    ADatePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case TIME: {
+                    ATimePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case DATETIME: {
+                    ADateTimePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case DURATION: {
+                    ADurationPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case POINT: {
+                    APointPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case POINT3D: {
+                    APoint3DPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case LINE: {
+                    ALinePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case POLYGON: {
+                    APolygonPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case CIRCLE: {
+                    ACirclePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case RECTANGLE: {
+                    ARectanglePrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                case STRING: {
+                    AStringPrinter.INSTANCE.print(b, s, l, ps);
+                    break;
+                }
+                default: {
+                    throw new NotImplementedException("No printer for type " + typeTag);
+                }
+            }
+            return null;
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/ARecordPrinter.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/ARecordPrinter.java
new file mode 100644
index 0000000..e15f9c0
--- /dev/null
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/pointables/printer/json/ARecordPrinter.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009-2010 by The Regents of the University of California
+ * 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 from
+ * 
+ *     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 edu.uci.ics.asterix.om.pointables.printer.json;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.List;
+
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.om.pointables.ARecordPointable;
+import edu.uci.ics.asterix.om.pointables.base.IVisitablePointable;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.EnumDeserializer;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+
+/**
+ * This class is to print the content of a record. It is ONLY visible to
+ * APrintVisitor.
+ */
+class ARecordPrinter {
+    private static String LEFT_PAREN = "{ ";
+    private static String RIGHT_PAREN = " }";
+    private static String COMMA = ", ";
+    private static String COLON = ": ";
+
+    private final Pair<PrintStream, ATypeTag> nameVisitorArg = new Pair<PrintStream, ATypeTag>(null, ATypeTag.STRING);
+    private final Pair<PrintStream, ATypeTag> itemVisitorArg = new Pair<PrintStream, ATypeTag>(null, null);
+
+    public ARecordPrinter() {
+
+    }
+
+    public void printRecord(ARecordPointable recordAccessor, PrintStream ps, APrintVisitor visitor) throws IOException,
+            AsterixException {
+        List<IVisitablePointable> fieldNames = recordAccessor.getFieldNames();
+        List<IVisitablePointable> fieldTags = recordAccessor.getFieldTypeTags();
+        List<IVisitablePointable> fieldValues = recordAccessor.getFieldValues();
+
+        nameVisitorArg.first = ps;
+        itemVisitorArg.first = ps;
+
+        // print the beginning part
+        ps.print(LEFT_PAREN);
+
+        // print field 0 to n-2
+        for (int i = 0; i < fieldNames.size() - 1; i++) {
+            printField(ps, visitor, fieldNames, fieldTags, fieldValues, i);
+            // print the comma
+            ps.print(COMMA);
+        }
+
+        // print field n-1
+        if (fieldValues.size() > 0) {
+            printField(ps, visitor, fieldNames, fieldTags, fieldValues, fieldValues.size() - 1);
+        }
+
+        // print the end part
+        ps.print(RIGHT_PAREN);
+    }
+
+    private void printField(PrintStream ps, APrintVisitor visitor, List<IVisitablePointable> fieldNames,
+            List<IVisitablePointable> fieldTags, List<IVisitablePointable> fieldValues, int i) throws AsterixException {
+        IVisitablePointable itemTypeTag = fieldTags.get(i);
+        IVisitablePointable item = fieldValues.get(i);
+        ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(itemTypeTag.getByteArray()[itemTypeTag
+                .getStartOffset()]);
+        itemVisitorArg.second = item.getLength() <= 1 ? ATypeTag.NULL : typeTag;
+
+        // print field name
+        fieldNames.get(i).accept(visitor, nameVisitorArg);
+        ps.print(COLON);
+        // print field value
+        item.accept(visitor, itemVisitorArg);
+    }
+}