blob: 10946bfe7e80680fd10b5481bccb39c993f71b96 [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.cmd;
import java.io.StringReader;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import jdk.jfr.ValueDescriptor;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedObject;
import jdk.jfr.consumer.RecordingFile;
import jdk.test.lib.process.OutputAnalyzer;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/*
* @test
* @key jfr
* @summary Tests print --xml
*
* @library /test/lib /test/jdk
* @modules java.scripting
* java.xml
* jdk.jfr
*
* @run main/othervm jdk.jfr.cmd.TestPrintXML
*/
public class TestPrintXML {
public static void main(String... args) throws Exception {
Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath();
OutputAnalyzer output = ExecuteHelper.run("print", "--xml", recordingFile.toString());
String xml = output.getStdout();
System.out.println(xml);
// Parse XML string
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser sp = factory.newSAXParser();
XMLReader xr = sp.getXMLReader();
RecordingHandler handler = new RecordingHandler();
xr.setContentHandler(handler);
xr.parse(new InputSource(new StringReader(xml)));
// Verify that all data was written correctly
Iterator<RecordedEvent> it = RecordingFile.readAllEvents(recordingFile).iterator();
for (XMLEvent xmlEvent : handler.events) {
RecordedEvent re = it.next();
if (!compare(re, xmlEvent.values)) {
System.out.println(re);
System.out.println(xmlEvent.values.toString());
throw new Exception("Event doesn't match");
}
}
}
@SuppressWarnings("unchecked")
static boolean compare(Object eventObject, Object xmlObject) {
if (eventObject == null) {
return xmlObject == null;
}
if (eventObject instanceof RecordedObject) {
RecordedObject re = (RecordedObject) eventObject;
Map<String, Object> xmlMap = (Map<String, Object>) xmlObject;
List<ValueDescriptor> fields = re.getFields();
if (fields.size() != xmlMap.size()) {
return false;
}
for (ValueDescriptor v : fields) {
String name = v.getName();
if (!compare(re.getValue(name), xmlMap.get(name))) {
return false;
}
}
return true;
}
if (eventObject.getClass().isArray()) {
Object[] array = (Object[]) eventObject;
Object[] xmlArray = (Object[]) xmlObject;
if (array.length != xmlArray.length) {
return false;
}
for (int i = 0; i < array.length; i++) {
if (!compare(array[i], xmlArray[i])) {
return false;
}
}
return true;
}
String s1 = String.valueOf(eventObject);
String s2 = (String) xmlObject;
return s1.equals(s2);
}
static class XMLEvent {
String name;
Instant startTime;
Duration duration;
Map<String, Object> values = new HashMap<>();
XMLEvent(String name, Instant startTime, Duration duration) {
this.name = name;
this.startTime = startTime;
this.duration = duration;
}
}
public static final class RecordingHandler extends DefaultHandler {
private Stack<Object> objects = new Stack<>();
private Stack<SimpleEntry<String, String>> elements = new Stack<>();
private List<XMLEvent> events = new ArrayList<>();
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
elements.push(new SimpleEntry<>(attrs.getValue("name"), attrs.getValue("index")));
switch (qName) {
case "null":
objects.pop();
objects.push(null);
break;
case "event":
Instant startTime = Instant.parse(attrs.getValue("startTime"));
Duration duration = Duration.parse(attrs.getValue("duration"));
objects.push(new XMLEvent(attrs.getValue("name"), startTime, duration));
break;
case "struct":
objects.push(new HashMap<String, Object>());
break;
case "array":
objects.push(new Object[Integer.parseInt(attrs.getValue("size"))]);
break;
case "value":
objects.push(new StringBuilder());
break;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!objects.isEmpty()) {
Object o = objects.peek();
if (o instanceof StringBuilder) {
((StringBuilder) o).append(ch, start, length);
}
}
}
@SuppressWarnings("unchecked")
@Override
public void endElement(String uri, String localName, String qName) {
SimpleEntry<String, String> element = elements.pop();
switch (qName) {
case "event":
case "struct":
case "array":
case "value":
String name = element.getKey();
Object value = objects.pop();
if (objects.isEmpty()) {
events.add((XMLEvent) value);
return;
}
if (value instanceof StringBuilder) {
value = ((StringBuilder) value).toString();
}
Object parent = objects.peek();
if (parent instanceof XMLEvent) {
((XMLEvent) parent).values.put(name, value);
}
if (parent instanceof Map) {
((Map<String, Object>) parent).put(name, value);
}
if (parent != null && parent.getClass().isArray()) {
int index = Integer.parseInt(element.getValue());
((Object[]) parent)[index] = value;
}
}
}
}
}