1 /* 2 * Copyright (c) 2018, 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.event.io; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.net.Socket; 31 32 import jdk.jfr.consumer.RecordedEvent; 33 import jdk.jfr.consumer.RecordedThread; 34 import jdk.testlibrary.jfr.EventField; 35 import jdk.testlibrary.jfr.EventNames; 36 import jdk.testlibrary.jfr.Events; 37 38 // Contains data from a JFR IO event. 39 public class IOEvent { 40 public final String thread; 41 public final EventType eventType; 42 public final long size; 43 public final String address; // Name of file or socket address. 44 public final boolean endOfStream; 45 46 // Constructor is private. Use IOEvent.create... 47 private IOEvent(String thread, EventType eventType, long size, String address, boolean endOfStream) { 48 this.thread = thread; 49 this.eventType = eventType; 50 this.size = size; 51 this.address = address; 52 this.endOfStream = endOfStream; 53 } 54 55 @Override 56 public String toString() { 57 String key = String.format("thread: %s, type: %s, size: %d, address: %s endOfStream: %s", thread, eventType, size, address, endOfStream); 58 return key; 59 } 60 61 @Override 62 public boolean equals(Object object) { 63 if (object == null || !(object instanceof IOEvent)) { 64 return false; 65 } 66 return toString().equals(object.toString()); 67 } 68 69 @Override 70 public int hashCode() { 71 return toString().hashCode(); 72 } 73 74 public static final String EVENT_UNKNOWN = "unknown-event??"; 75 public static final String EVENT_FILE_FORCE = EventNames.FileForce; 76 public static final String EVENT_FILE_READ = EventNames.FileRead; 77 public static final String EVENT_FILE_WRITE = EventNames.FileWrite; 78 public static final String EVENT_SOCKET_READ = EventNames.SocketRead; 79 public static final String EVENT_SOCKET_WRITE = EventNames.SocketWrite; 80 81 public enum EventType { UnknownEvent, FileForce, FileRead, FileWrite, SocketRead, SocketWrite } 82 83 private static final String[] eventPaths = { 84 EVENT_UNKNOWN, EVENT_FILE_FORCE, EVENT_FILE_READ, EVENT_FILE_WRITE, EVENT_SOCKET_READ, EVENT_SOCKET_WRITE 85 }; 86 87 public static boolean isWriteEvent(EventType eventType) { 88 return (eventType == EventType.SocketWrite || eventType == EventType.FileWrite); 89 } 90 91 public static boolean isReadEvent(EventType eventType) { 92 return (eventType == EventType.SocketRead || eventType == EventType.FileRead); 93 } 94 95 public static boolean isFileEvent(EventType eventType) { 96 return (eventType == EventType.FileForce || eventType == EventType.FileWrite || eventType == EventType.FileRead); 97 } 98 99 public static IOEvent createSocketWriteEvent(long size, Socket s) { 100 if (size < 0) { 101 size = 0; 102 } 103 return new IOEvent(Thread.currentThread().getName(), EventType.SocketWrite, size, getAddress(s), false); 104 } 105 106 public static IOEvent createSocketReadEvent(long size, Socket s) { 107 boolean endOfStream = false; 108 if (size < 0) { 109 size = 0; 110 endOfStream = true; 111 } 112 return new IOEvent(Thread.currentThread().getName(), EventType.SocketRead, size, getAddress(s), endOfStream); 113 } 114 115 public static IOEvent createFileForceEvent(File file) { 116 String address = null; 117 try { 118 address = file.getCanonicalPath(); 119 } catch(IOException ex) { 120 throw new RuntimeException(); 121 } 122 return new IOEvent(Thread.currentThread().getName(), EventType.FileForce, 0, address, false); 123 } 124 125 public static IOEvent createFileReadEvent(long size, File file) { 126 boolean endOfStream = false; 127 if (size < 0) { 128 endOfStream = true; 129 size = 0; 130 } 131 String address = null; 132 try { 133 address = file.getCanonicalPath(); 134 } catch(IOException ex) { 135 throw new RuntimeException(); 136 } 137 return new IOEvent(Thread.currentThread().getName(), EventType.FileRead, size, address, endOfStream); 138 } 139 140 public static IOEvent createFileWriteEvent(long size, File file) { 141 if (size < 0) { 142 size = 0; 143 } 144 String address = null; 145 try { 146 address = file.getCanonicalPath(); 147 } catch(IOException ex) { 148 throw new RuntimeException(); 149 } 150 return new IOEvent(Thread.currentThread().getName(), EventType.FileWrite, size, address, false); 151 } 152 153 public static EventType getEventType(RecordedEvent event) { 154 final String path = event.getEventType().getName(); 155 for (int i = 0; i < eventPaths.length; ++i) { 156 if (path.endsWith(eventPaths[i])) { 157 return EventType.values()[i]; 158 } 159 } 160 return EventType.UnknownEvent; 161 } 162 163 public static IOEvent createTestEvent(RecordedEvent event) { 164 EventType eventType = getEventType(event); 165 if (eventType == EventType.UnknownEvent) { 166 return null; 167 } 168 EventField ev = Events.assertField(event, "eventThread"); 169 RecordedThread t = ev.getValue(); 170 String thread = t.getJavaName(); 171 long size = 0L; 172 if (isWriteEvent(eventType)) { 173 size = Events.assertField(event, "bytesWritten").getValue(); 174 } else if (isReadEvent(eventType)) { 175 size = Events.assertField(event, "bytesRead").getValue(); 176 } 177 String address = getEventAddress(event); 178 boolean endOfStream = false; 179 if (event.hasField("endOfStream")) { 180 endOfStream = event.getValue("endOfStream"); 181 } 182 if (event.hasField("endOfFile")) { 183 endOfStream = event.getValue("endOfFile"); 184 } 185 return new IOEvent(thread, eventType, size, address, endOfStream); 186 } 187 188 public static String getEventAddress(RecordedEvent event) { 189 if (isFileEvent(getEventType(event))) { 190 String address = Events.assertField(event, "path").getValue(); 191 // must ensure canonical format 192 String canonical_path = null; 193 try { 194 canonical_path = new File(address).getCanonicalPath(); 195 } catch (IOException ex) { 196 throw new RuntimeException(); 197 } 198 return canonical_path; 199 } else { 200 return String.format("%s/%s:%d", 201 event.getValue("host"), 202 event.getValue("address"), 203 event.getValue("port")); 204 } 205 } 206 207 private static String getAddress(Socket s) { 208 return s.getInetAddress().toString() + ":" + s.getPort(); 209 } 210 }