1 /*
   2  * Copyright (c) 2016, 2019, 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.IOException;
  29 import java.io.PrintWriter;
  30 import java.nio.file.Path;
  31 
  32 import jdk.jfr.EventType;
  33 import jdk.jfr.ValueDescriptor;
  34 import jdk.jfr.consumer.RecordedEvent;
  35 import jdk.jfr.consumer.RecordedObject;
  36 import jdk.jfr.consumer.RecordingFile;
  37 
  38 final class XMLWriter extends StructuredWriter {
  39 
  40     public XMLWriter(PrintWriter destination) {
  41         super(destination);
  42     }
  43 
  44     public void print(Path source) throws IOException {
  45         try (RecordingFile es = new RecordingFile(source)) {
  46             println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  47             println("<recording>");
  48             indent();
  49             printIndent();
  50             println("<events>");
  51             indent();
  52             while (es.hasMoreEvents()) {
  53                 printEvent(es.readEvent());
  54                 flush();
  55             }
  56             retract();
  57             printIndent();
  58             println("</events>");
  59             retract();
  60             println("</recording>");
  61             flush();
  62         }
  63     }
  64 
  65     private void printEvent(RecordedEvent e) throws IOException {
  66         EventType type = e.getEventType();
  67         printIndent();
  68         print("<event");
  69         printAttribute("typeId", String.valueOf(type.getId()));
  70         printAttribute("name", type.getName());
  71         printAttribute("startTime",e.getStartTime().toString());
  72         printAttribute("duration", e.getDuration().toString());
  73         print(">");
  74         printObject(e);
  75         printIndent();
  76         println("</event>");
  77         println();
  78     }
  79 
  80     private void printAttribute(String name, String value) {
  81         print(" ", name, "=\"", value, "\"");
  82     }
  83 
  84     public void printObject(RecordedObject struct) {
  85         println();
  86         indent();
  87         for (ValueDescriptor v : struct.getFields()) {
  88             printValueDescriptor(v, struct.getValue(v.getName()), -1);
  89         }
  90         retract();
  91     }
  92 
  93     private void printArray(ValueDescriptor v, Object[] array) {
  94         println();
  95         indent();
  96         for (int index = 0; index < array.length; index++) {
  97             printValueDescriptor(v, array[index], index);
  98         }
  99         retract();
 100     }
 101 
 102     private void printValueDescriptor(ValueDescriptor vd, Object value, int index) {
 103         boolean arrayElement = index != -1;
 104         String name = arrayElement ? null : vd.getName();
 105         if (vd.isArray() && !arrayElement) {
 106             if (printBeginElement("array", name, value, index)) {
 107                 printArray(vd, (Object[]) value);
 108                 printIndent();
 109                 printEndElement("array");
 110             }
 111             return;
 112         }
 113         if (!vd.getFields().isEmpty()) {
 114             if (printBeginElement("struct", name, value, index)) {
 115                 printObject((RecordedObject) value);
 116                 printIndent();
 117                 printEndElement("struct");
 118             }
 119             return;
 120         }
 121         if (printBeginElement("value", name, value, index)) {
 122             printEscaped(String.valueOf(value));
 123             printEndElement("value");
 124         }
 125     }
 126 
 127     private boolean printBeginElement(String elementName, String name, Object value, int index) {
 128         printIndent();
 129         print("<", elementName);
 130         if (name != null) {
 131             printAttribute("name", name);
 132         }
 133         if (index != -1) {
 134             printAttribute("index", Integer.toString(index));
 135         }
 136         if (value == null) {
 137             print("><null/></");
 138             print(elementName);
 139             println(">");
 140             return false;
 141         }
 142         if (value.getClass().isArray()) {
 143             Object[] array = (Object[]) value;
 144             printAttribute("size", Integer.toString(array.length));
 145         }
 146         print(">");
 147         return true;
 148     }
 149 
 150     private void printEndElement(String elementName) {
 151         print("</");
 152         print(elementName);
 153         println(">");
 154     }
 155 
 156     private void printEscaped(String text) {
 157         for (int i = 0; i < text.length(); i++) {
 158             printEscaped(text.charAt(i));
 159         }
 160     }
 161 
 162     private void printEscaped(char c) {
 163         if (c == 34) {
 164             print("&quot;");
 165             return;
 166         }
 167         if (c == 38) {
 168             print("&amp;");
 169             return;
 170         }
 171         if (c == 39) {
 172             print("&apos;");
 173             return;
 174         }
 175         if (c == 60) {
 176             print("&lt;");
 177             return;
 178         }
 179         if (c == 62) {
 180             print("&gt;");
 181             return;
 182         }
 183         if (c > 0x7F) {
 184             print("&#");
 185             print((int) c);
 186             print(';');
 187             return;
 188         }
 189         print(c);
 190     }
 191 }