1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.internal.cmd; 27 28 import java.io.FileNotFoundException; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.nio.file.Path; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.StringJoiner; 37 38 import jdk.jfr.AnnotationElement; 39 import jdk.jfr.ValueDescriptor; 40 import jdk.jfr.consumer.RecordedEvent; 41 import jdk.jfr.consumer.RecordedObject; 42 import jdk.jfr.consumer.RecordingFile; 43 import jdk.jfr.internal.PrivateAccess; 44 import jdk.jfr.internal.Type; 45 import jdk.jfr.internal.consumer.ChunkHeader; 46 import jdk.jfr.internal.consumer.RecordingInput; 47 48 public final class PrettyWriter extends StructuredWriter { 49 50 public PrettyWriter(PrintWriter destination) { 51 super(destination); 52 } 53 54 void print(Path source) throws FileNotFoundException, IOException { 55 try (RecordingInput input = new RecordingInput(source.toFile())) { 56 HashSet<Type> typeSet = new HashSet<>(); 57 for (ChunkHeader ch = new ChunkHeader(input); !ch.isLastChunk(); ch = ch.nextHeader()) { 58 typeSet.addAll(ch.readMetadata().getTypes()); 59 } 60 List<Type> types = new ArrayList<>(typeSet); 61 Collections.sort(types, (c1, c2) -> Long.compare(c1.getId(), c2.getId())); 62 for (Type t : types) { 63 printType(t); 64 } 65 flush(); 66 } 67 68 try (RecordingFile es = new RecordingFile(source)) { 69 while (es.hasMoreEvents()) { 70 print(es.readEvent()); 71 flush(); 72 } 73 } 74 flush(); 75 } 76 77 private void printType(Type t) throws IOException { 78 print("// id: "); 79 println(String.valueOf(t.getId())); 80 int commentIndex = t.getName().length() + 10; 81 String typeName = t.getName(); 82 int index = typeName.lastIndexOf("."); 83 if (index != -1) { 84 println("package " + typeName.substring(0, index) + ";"); 85 } 86 printAnnotations(commentIndex, t.getAnnotationElements()); 87 print("class " + typeName.substring(index + 1)); 88 String superType = t.getSuperType(); 89 if (superType != null) { 90 print(" extends " + superType); 91 } 92 println(" {"); 93 indent(); 94 for (ValueDescriptor v : t.getFields()) { 95 printField(commentIndex, v); 96 } 97 retract(); 98 println("}"); 99 println(); 100 } 101 102 private void printField(int commentIndex, ValueDescriptor v) throws IOException { 103 println(); 104 printAnnotations(commentIndex, v.getAnnotationElements()); 105 printIndent(); 106 Type vType = PrivateAccess.getInstance().getType(v); 107 if (Type.SUPER_TYPE_SETTING.equals(vType.getSuperType())) { 108 print("static "); 109 } 110 print(makeSimpleType(v.getTypeName())); 111 if (v.isArray()) { 112 print("[]"); 113 } 114 print(" "); 115 print(v.getName()); 116 print(";"); 117 printCommentRef(commentIndex, v.getTypeId()); 118 } 119 120 private void printCommentRef(int commentIndex, long typeId) throws IOException { 121 int column = getColumn(); 122 if (column > commentIndex) { 123 print(" "); 124 } else { 125 while (column < commentIndex) { 126 print(" "); 127 column++; 128 } 129 } 130 println(" // id=" + typeId); 131 } 132 133 private void printAnnotations(int commentIndex, List<AnnotationElement> annotations) throws IOException { 134 for (AnnotationElement a : annotations) { 135 printIndent(); 136 print("@"); 137 print(makeSimpleType(a.getTypeName())); 138 List<ValueDescriptor> vs = a.getValueDescriptors(); 139 if (!vs.isEmpty()) { 140 print("("); 141 printAnnotation(a); 142 print(")"); 143 printCommentRef(commentIndex, a.getTypeId()); 144 } else { 145 println(); 146 } 147 } 148 } 149 150 private void printAnnotation(AnnotationElement a) throws IOException { 151 StringJoiner sj = new StringJoiner(", "); 152 for (ValueDescriptor v : a.getValueDescriptors()) { 153 StringBuilder sb = new StringBuilder(); 154 Object o = a.getValue(v.getName()); 155 if (o instanceof String) { 156 sb.append("\""); 157 sb.append((String) o); 158 sb.append("\""); 159 } else { 160 sb.append(o); 161 } 162 sj.add(sb.toString()); 163 } 164 print(sj.toString()); 165 } 166 167 private String makeSimpleType(String typeName) { 168 int index = typeName.lastIndexOf("."); 169 return typeName.substring(index + 1); 170 } 171 172 public void print(RecordedEvent event) throws IOException { 173 print(makeSimpleType(event.getEventType().getName()), " "); 174 print((RecordedObject) event, ""); 175 } 176 177 public void print(RecordedObject struct, String postFix) throws IOException { 178 println("{"); 179 indent(); 180 for (ValueDescriptor v : struct.getFields()) { 181 printIndent(); 182 print(v.getName(), " = "); 183 printValue(struct.getValue(v.getName()), ""); 184 } 185 retract(); 186 printIndent(); 187 println("}" + postFix); 188 } 189 190 private void printArray(Object[] array) throws IOException { 191 println("["); 192 indent(); 193 for (int i = 0; i < array.length; i++) { 194 printIndent(); 195 printValue(array[i], i + 1 < array.length ? ", " : ""); 196 } 197 retract(); 198 printIndent(); 199 println("]"); 200 } 201 202 private void printValue(Object value, String postFix) throws IOException { 203 if (value == null) { 204 println("null" + postFix); 205 } else if (value instanceof RecordedObject) { 206 print((RecordedObject) value, postFix); 207 } else if (value.getClass().isArray()) { 208 printArray((Object[]) value); 209 } else { 210 String text = String.valueOf(value); 211 if (value instanceof String) { 212 text = "\"" + text + "\""; 213 } 214 println(text); 215 } 216 } 217 }