src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java
changeset 50113 caf115bb98ad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,236 @@
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.StringJoiner;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.jfr.internal.PrivateAccess;
+import jdk.jfr.internal.Type;
+import jdk.jfr.internal.consumer.ChunkHeader;
+import jdk.jfr.internal.consumer.RecordingInput;
+
+public final class PrettyWriter extends StructuredWriter {
+
+    public PrettyWriter(PrintWriter destination) {
+        super(destination);
+    }
+
+    void print(Path source) throws FileNotFoundException, IOException {
+        try (RecordingInput input = new RecordingInput(source.toFile())) {
+            HashSet<Type> typeSet = new HashSet<>();
+            for (ChunkHeader ch = new ChunkHeader(input); !ch.isLastChunk(); ch = ch.nextHeader()) {
+                typeSet.addAll(ch.readMetadata().getTypes());
+            }
+            List<Type> types = new ArrayList<>(typeSet);
+            Collections.sort(types, (c1, c2) -> Long.compare(c1.getId(), c2.getId()));
+            for (Type t : types) {
+                printType(t);
+            }
+            flush();
+        }
+
+        try (RecordingFile es = new RecordingFile(source)) {
+            while (es.hasMoreEvents()) {
+                print(es.readEvent());
+                flush();
+            }
+        }
+        flush();
+    }
+
+    public void printType(Type t) throws IOException {
+        print("// id: ");
+        println(String.valueOf(t.getId()));
+        int commentIndex = t.getName().length() + 10;
+        String typeName = t.getName();
+        int index = typeName.lastIndexOf(".");
+        if (index != -1) {
+            println("package " + typeName.substring(0, index) + ";");
+        }
+        printAnnotations(commentIndex, t.getAnnotationElements());
+        print("class " + typeName.substring(index + 1));
+        String superType = t.getSuperType();
+        if (superType != null) {
+            print(" extends " + superType);
+        }
+        println(" {");
+        indent();
+        for (ValueDescriptor v : t.getFields()) {
+            printField(commentIndex, v);
+        }
+        retract();
+        println("}");
+        println();
+    }
+
+    private void printField(int commentIndex, ValueDescriptor v) throws IOException {
+        println();
+        printAnnotations(commentIndex, v.getAnnotationElements());
+        printIndent();
+        Type vType = PrivateAccess.getInstance().getType(v);
+        if (Type.SUPER_TYPE_SETTING.equals(vType.getSuperType())) {
+            print("static ");
+        }
+        print(makeSimpleType(v.getTypeName()));
+        if (v.isArray()) {
+            print("[]");
+        }
+        print(" ");
+        print(v.getName());
+        print(";");
+        printCommentRef(commentIndex, v.getTypeId());
+    }
+
+    private void printCommentRef(int commentIndex, long typeId) throws IOException {
+        int column = getColumn();
+        if (column > commentIndex) {
+            print("  ");
+        } else {
+            while (column < commentIndex) {
+                print(" ");
+                column++;
+            }
+        }
+        println(" // id=" + typeId);
+    }
+
+    private void printAnnotations(int commentIndex, List<AnnotationElement> annotations) throws IOException {
+        for (AnnotationElement a : annotations) {
+            printIndent();
+            print("@");
+            print(makeSimpleType(a.getTypeName()));
+            List<ValueDescriptor> vs = a.getValueDescriptors();
+            if (!vs.isEmpty()) {
+                printAnnotation(a);
+                printCommentRef(commentIndex, a.getTypeId());
+            } else {
+                println();
+            }
+        }
+    }
+
+    private void printAnnotation(AnnotationElement a) throws IOException {
+        StringJoiner sj = new StringJoiner(", ", "(", ")");
+        List<ValueDescriptor> vs = a.getValueDescriptors();
+        for (ValueDescriptor v : vs) {
+            Object o = a.getValue(v.getName());
+            if (vs.size() == 1 && v.getName().equals("value")) {
+                sj.add(textify(o));
+            } else {
+                sj.add(v.getName() + "=" + textify(o));
+            }
+        }
+        print(sj.toString());
+    }
+
+    private String textify(Object o) {
+        if (o.getClass().isArray()) {
+            Object[] array = (Object[]) o;
+            if (array.length == 1) {
+                return quoteIfNeeded(array[0]);
+            }
+            StringJoiner s = new StringJoiner(", ", "{", "}") ;
+            for (Object ob : array) {
+                s.add(quoteIfNeeded(ob));
+            }
+            return s.toString();
+        } else {
+            return quoteIfNeeded(o);
+        }
+    }
+
+    private String quoteIfNeeded(Object o) {
+        if (o instanceof String) {
+            return "\"" + o + "\"";
+        } else {
+            return String.valueOf(o);
+        }
+    }
+
+    private String makeSimpleType(String typeName) {
+        int index = typeName.lastIndexOf(".");
+        return typeName.substring(index + 1);
+    }
+
+    public void print(RecordedEvent event) throws IOException {
+        print(makeSimpleType(event.getEventType().getName()), " ");
+        print((RecordedObject) event, "");
+    }
+
+    public void print(RecordedObject struct, String postFix) throws IOException {
+        println("{");
+        indent();
+        for (ValueDescriptor v : struct.getFields()) {
+            printIndent();
+            print(v.getName(), " = ");
+            printValue(struct.getValue(v.getName()), "");
+        }
+        retract();
+        printIndent();
+        println("}" + postFix);
+    }
+
+    private void printArray(Object[] array) throws IOException {
+        println("[");
+        indent();
+        for (int i = 0; i < array.length; i++) {
+            printIndent();
+            printValue(array[i], i + 1 < array.length ? ", " : "");
+        }
+        retract();
+        printIndent();
+        println("]");
+    }
+
+    private void printValue(Object value, String postFix) throws IOException {
+        if (value == null) {
+            println("null" + postFix);
+        } else if (value instanceof RecordedObject) {
+            print((RecordedObject) value, postFix);
+        } else if (value.getClass().isArray()) {
+            printArray((Object[]) value);
+        } else {
+            String text = String.valueOf(value);
+            if (value instanceof String) {
+                text = "\"" + text + "\"";
+            }
+            println(text);
+        }
+    }
+}