blob: 0e008c87325063bb5e6a186379181e0c88c2418c [file] [log] [blame]
/*
* 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.tool;
import java.io.PrintWriter;
import java.util.List;
import jdk.jfr.EventType;
import jdk.jfr.ValueDescriptor;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordedObject;
final class JSONWriter extends EventPrintWriter {
private boolean first = true;
public JSONWriter(PrintWriter writer) {
super(writer);
}
@Override
protected void printBegin() {
printObjectBegin();
printDataStructureName("recording");
printObjectBegin();
printDataStructureName("events");
printArrayBegin();
}
@Override
protected void print(List<RecordedEvent> events) {
for (RecordedEvent event : events) {
printNewDataStructure(first, true, null);
printEvent(event);
flush(false);
first = false;
}
}
@Override
protected void printEnd() {
printArrayEnd();;
printObjectEnd();
printObjectEnd();
}
private void printEvent(RecordedEvent event) {
printObjectBegin();
EventType type = event.getEventType();
printValue(true, false, "type", type.getName());
printNewDataStructure(false, false, "values");
printObjectBegin();
boolean first = true;
for (ValueDescriptor v : event.getFields()) {
printValueDescriptor(first, false, v, getValue(event, v));
first = false;
}
printObjectEnd();
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, getValue(object, v));
first = false;
}
printObjectEnd();
}
private void printArray(ValueDescriptor v, Object[] array) {
printArrayBegin();
boolean first = true;
int depth = 0;
for (Object arrayElement : array) {
if (!(arrayElement instanceof RecordedFrame) || depth < getStackDepth()) {
printValueDescriptor(first, true, v, arrayElement);
}
depth++;
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);
}
}