src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java
changeset 50113 caf115bb98ad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.cmd;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+
+import jdk.jfr.EventType;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+
+final class JSONWriter extends StructuredWriter {
+
+    public JSONWriter(PrintWriter writer) {
+        super(writer);
+    }
+
+    public void print(Path source) throws IOException {
+        try (RecordingFile es = new RecordingFile(source)) {
+            printObjectBegin();
+            printRecording(es);
+            printObjectEnd();
+            flush();
+        }
+    }
+
+    private void printRecording(RecordingFile es) throws IOException {
+        printDataStructureName("recording");
+        printObjectBegin();
+        printEvents(es);
+        printObjectEnd();
+    }
+
+    private void printEvents(RecordingFile es) throws IOException {
+        printDataStructureName("events");
+        printArrayBegin();
+        boolean first = true;
+        while (es.hasMoreEvents()) {
+            RecordedEvent e = es.readEvent();
+            printNewDataStructure(first, true, null);
+            printEvent(e);
+            flush();
+            first = false;
+        }
+        printArrayEnd();
+    }
+
+    private void printEvent(RecordedEvent e) {
+        printObjectBegin();
+        EventType type = e.getEventType();
+        printValue(true, false, "name", type.getName());
+        printValue(false, false, "typeId", type.getId());
+        printValue(false, false, "startTime", e.getStartTime());
+        printValue(false, false, "duration", e.getDuration());
+        printNewDataStructure(false, false, "values");
+        printObject(e);
+        printObjectEnd();
+    }
+
+    void printValue(boolean first, boolean arrayElement, String name, Object value) {
+        printNewDataStructure(first, arrayElement, name);
+        if (!printIfNull(value)) {
+            if (value instanceof Boolean) {
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Double) {
+                Double dValue = (Double) value;
+                if (Double.isNaN(dValue) || Double.isInfinite(dValue)) {
+                    printNull();
+                    return;
+                }
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Float) {
+                Float fValue = (Float) value;
+                if (Float.isNaN(fValue) || Float.isInfinite(fValue)) {
+                    printNull();
+                    return;
+                }
+                printAsString(value);
+                return;
+            }
+            if (value instanceof Number) {
+                printAsString(value);
+                return;
+            }
+            print("\"");
+            printEscaped(String.valueOf(value));
+            print("\"");
+        }
+    }
+
+    public void printObject(RecordedObject object) {
+        printObjectBegin();
+        boolean first = true;
+        for (ValueDescriptor v : object.getFields()) {
+            printValueDescriptor(first, false, v, object.getValue(v.getName()));
+            first = false;
+        }
+        printObjectEnd();
+    }
+
+    private void printArray(ValueDescriptor v, Object[] array) {
+        printArrayBegin();
+        boolean first = true;
+        for (Object arrayElement : array) {
+            printValueDescriptor(first, true, v, arrayElement);
+            first = false;
+        }
+        printArrayEnd();
+    }
+
+    private void printValueDescriptor(boolean first, boolean arrayElement, ValueDescriptor vd, Object value) {
+        if (vd.isArray() && !arrayElement) {
+            printNewDataStructure(first, arrayElement, vd.getName());
+            if (!printIfNull(value)) {
+                printArray(vd, (Object[]) value);
+            }
+            return;
+        }
+        if (!vd.getFields().isEmpty()) {
+            printNewDataStructure(first, arrayElement, vd.getName());
+            if (!printIfNull(value)) {
+                printObject((RecordedObject) value);
+            }
+            return;
+        }
+        printValue(first, arrayElement, vd.getName(), value);
+    }
+
+    private void printNewDataStructure(boolean first, boolean arrayElement, String name) {
+        if (!first) {
+            print(", ");
+            if (!arrayElement) {
+                println();
+            }
+        }
+        if (!arrayElement) {
+            printDataStructureName(name);
+        }
+    }
+
+    private boolean printIfNull(Object value) {
+        if (value == null) {
+            printNull();
+            return true;
+        }
+        return false;
+    }
+
+    private void printNull() {
+        print("null");
+    }
+
+    private void printDataStructureName(String text) {
+        printIndent();
+        print("\"");
+        print(text);
+        print("\": ");
+    }
+
+    private void printObjectEnd() {
+        retract();
+        println();
+        printIndent();
+        print("}");
+    }
+
+    private void printObjectBegin() {
+        println("{");
+        indent();
+    }
+
+    private void printArrayEnd() {
+        print("]");
+    }
+
+    private void printArrayBegin() {
+        print("[");
+    }
+
+    private void printEscaped(String text) {
+        for (int i = 0; i < text.length(); i++) {
+            printEscaped(text.charAt(i));
+        }
+    }
+
+    private void printEscaped(char c) {
+        if (c == '\b') {
+            print("\\b");
+            return;
+        }
+        if (c == '\n') {
+            print("\\n");
+            return;
+        }
+        if (c == '\t') {
+            print("\\t");
+            return;
+        }
+        if (c == '\f') {
+            print("\\f");
+            return;
+        }
+        if (c == '\r') {
+            print("\\r");
+            return;
+        }
+        if (c == '\"') {
+            print("\\\"");
+            return;
+        }
+        if (c == '\\') {
+            print("\\\\");
+            return;
+        }
+        if (c == '/') {
+            print("\\/");
+            return;
+        }
+        if (c > 0x7F || c < 32) {
+            print("\\u");
+            // 0x10000 will pad with zeros.
+            print(Integer.toHexString(0x10000 + (int) c).substring(1));
+            return;
+        }
+        print(c);
+    }
+
+}