/* * Copyright (c) 2018, 2019, 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.testlibrary.jfr; import java.io.File; import java.io.IOException; import java.net.Socket; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedThread; import jdk.testlibrary.jfr.EventField; import jdk.testlibrary.jfr.EventNames; import jdk.testlibrary.jfr.Events; // Contains data from a JFR IO event. public class IOEvent { public final String thread; public final EventType eventType; public final long size; public final String address; // Name of file or socket address. public final boolean endOfStream; // Constructor is private. Use IOEvent.create... private IOEvent(String thread, EventType eventType, long size, String address, boolean endOfStream) { this.thread = thread; this.eventType = eventType; this.size = size; this.address = address; this.endOfStream = endOfStream; } @Override public String toString() { String key = String.format("thread: %s, type: %s, size: %d, address: %s endOfStream: %s", thread, eventType, size, address, endOfStream); return key; } @Override public boolean equals(Object object) { if (object == null || !(object instanceof IOEvent)) { return false; } return toString().equals(object.toString()); } @Override public int hashCode() { return toString().hashCode(); } public static final String EVENT_UNKNOWN = "unknown-event??"; public static final String EVENT_FILE_FORCE = EventNames.FileForce; public static final String EVENT_FILE_READ = EventNames.FileRead; public static final String EVENT_FILE_WRITE = EventNames.FileWrite; public static final String EVENT_SOCKET_READ = EventNames.SocketRead; public static final String EVENT_SOCKET_WRITE = EventNames.SocketWrite; public enum EventType { UnknownEvent, FileForce, FileRead, FileWrite, SocketRead, SocketWrite } private static final String[] eventPaths = { EVENT_UNKNOWN, EVENT_FILE_FORCE, EVENT_FILE_READ, EVENT_FILE_WRITE, EVENT_SOCKET_READ, EVENT_SOCKET_WRITE }; public static boolean isWriteEvent(EventType eventType) { return (eventType == EventType.SocketWrite || eventType == EventType.FileWrite); } public static boolean isReadEvent(EventType eventType) { return (eventType == EventType.SocketRead || eventType == EventType.FileRead); } public static boolean isFileEvent(EventType eventType) { return (eventType == EventType.FileForce || eventType == EventType.FileWrite || eventType == EventType.FileRead); } public static IOEvent createSocketWriteEvent(long size, Socket s) { if (size < 0) { size = 0; } return new IOEvent(Thread.currentThread().getName(), EventType.SocketWrite, size, getAddress(s), false); } public static IOEvent createSocketReadEvent(long size, Socket s) { boolean endOfStream = false; if (size < 0) { size = 0; endOfStream = true; } return new IOEvent(Thread.currentThread().getName(), EventType.SocketRead, size, getAddress(s), endOfStream); } public static IOEvent createFileForceEvent(File file) { String address = null; try { address = file.getCanonicalPath(); } catch(IOException ex) { throw new RuntimeException(); } return new IOEvent(Thread.currentThread().getName(), EventType.FileForce, 0, address, false); } public static IOEvent createFileReadEvent(long size, File file) { boolean endOfStream = false; if (size < 0) { endOfStream = true; size = 0; } String address = null; try { address = file.getCanonicalPath(); } catch(IOException ex) { throw new RuntimeException(); } return new IOEvent(Thread.currentThread().getName(), EventType.FileRead, size, address, endOfStream); } public static IOEvent createFileWriteEvent(long size, File file) { if (size < 0) { size = 0; } String address = null; try { address = file.getCanonicalPath(); } catch(IOException ex) { throw new RuntimeException(); } return new IOEvent(Thread.currentThread().getName(), EventType.FileWrite, size, address, false); } public static EventType getEventType(RecordedEvent event) { final String path = event.getEventType().getName(); for (int i = 0; i < eventPaths.length; ++i) { if (path.endsWith(eventPaths[i])) { return EventType.values()[i]; } } return EventType.UnknownEvent; } public static IOEvent createTestEvent(RecordedEvent event) { EventType eventType = getEventType(event); if (eventType == EventType.UnknownEvent) { return null; } EventField ev = Events.assertField(event, "eventThread"); RecordedThread t = ev.getValue(); String thread = t.getJavaName(); long size = 0L; if (isWriteEvent(eventType)) { size = Events.assertField(event, "bytesWritten").getValue(); } else if (isReadEvent(eventType)) { size = Events.assertField(event, "bytesRead").getValue(); } String address = getEventAddress(event); boolean endOfStream = false; if (event.hasField("endOfStream")) { endOfStream = event.getValue("endOfStream"); } if (event.hasField("endOfFile")) { endOfStream = event.getValue("endOfFile"); } return new IOEvent(thread, eventType, size, address, endOfStream); } public static String getEventAddress(RecordedEvent event) { if (isFileEvent(getEventType(event))) { String address = Events.assertField(event, "path").getValue(); // must ensure canonical format String canonical_path = null; try { canonical_path = new File(address).getCanonicalPath(); } catch (IOException ex) { throw new RuntimeException(); } return canonical_path; } else { return String.format("%s/%s:%d", event.getValue("host"), event.getValue("address"), event.getValue("port")); } } private static String getAddress(Socket s) { return s.getInetAddress().toString() + ":" + s.getPort(); } }