1 /*
2  * Copyright (c) 2018, 2020, 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.test.lib.jfr.EventField;
35 import jdk.test.lib.jfr.EventNames;
36 import jdk.test.lib.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...
IOEvent(String thread, EventType eventType, long size, String address, boolean endOfStream)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
toString()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
equals(Object object)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
hashCode()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 
isWriteEvent(EventType eventType)87     public static boolean isWriteEvent(EventType eventType) {
88         return (eventType == EventType.SocketWrite || eventType == EventType.FileWrite);
89     }
90 
isReadEvent(EventType eventType)91     public static boolean isReadEvent(EventType eventType) {
92         return (eventType == EventType.SocketRead || eventType == EventType.FileRead);
93     }
94 
isFileEvent(EventType eventType)95     public static boolean isFileEvent(EventType eventType) {
96         return (eventType == EventType.FileForce || eventType == EventType.FileWrite || eventType == EventType.FileRead);
97     }
98 
createSocketWriteEvent(long size, Socket s)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 
createSocketReadEvent(long size, Socket s)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 
createFileForceEvent(File file)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 
createFileReadEvent(long size, File file)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 
createFileWriteEvent(long size, File file)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 
getEventType(RecordedEvent event)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 
createTestEvent(RecordedEvent event)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 
getEventAddress(RecordedEvent event)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 event.getValue("address") + ":"  + event.getValue("port");
201         }
202     }
203 
getAddress(Socket s)204     private static String getAddress(Socket s) {
205         return s.getInetAddress().getHostAddress() + ":" + s.getPort();
206     }
207 }
208