/* * 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 /lib / * * * @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 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 xmlMap = (Map) xmlObject; List 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 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 objects = new Stack<>(); private Stack> elements = new Stack<>(); private List 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()); 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 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) parent).put(name, value); } if (parent != null && parent.getClass().isArray()) { int index = Integer.parseInt(element.getValue()); ((Object[]) parent)[index] = value; } } } } }