50113
|
1 |
/*
|
|
2 |
* Copyright (c) 2018, 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.api.event.dynamic;
|
|
27 |
|
|
28 |
import java.io.IOException;
|
|
29 |
import java.lang.annotation.ElementType;
|
|
30 |
import java.lang.annotation.Retention;
|
|
31 |
import java.lang.annotation.RetentionPolicy;
|
|
32 |
import java.lang.annotation.Target;
|
|
33 |
import java.util.ArrayList;
|
|
34 |
import java.util.Collections;
|
|
35 |
import java.util.Comparator;
|
|
36 |
import java.util.HashMap;
|
|
37 |
import java.util.List;
|
|
38 |
import java.util.Map;
|
|
39 |
|
|
40 |
import jdk.jfr.AnnotationElement;
|
|
41 |
import jdk.jfr.Event;
|
|
42 |
import jdk.jfr.EventFactory;
|
|
43 |
import jdk.jfr.EventType;
|
|
44 |
import jdk.jfr.MetadataDefinition;
|
|
45 |
import jdk.jfr.Recording;
|
|
46 |
import jdk.jfr.ValueDescriptor;
|
|
47 |
import jdk.jfr.consumer.RecordedClass;
|
|
48 |
import jdk.jfr.consumer.RecordedEvent;
|
|
49 |
import jdk.jfr.consumer.RecordedThread;
|
|
50 |
import jdk.jfr.consumer.RecordingFile;
|
|
51 |
import jdk.test.lib.Asserts;
|
|
52 |
import jdk.test.lib.jfr.EventTypePrototype;
|
|
53 |
import jdk.test.lib.jfr.Events;
|
|
54 |
|
|
55 |
|
51214
|
56 |
/**
|
50113
|
57 |
* @test
|
|
58 |
* @key jfr
|
51214
|
59 |
* @requires vm.hasJFR
|
50113
|
60 |
* @library /test/lib
|
|
61 |
* @run main/othervm jdk.jfr.api.event.dynamic.TestEventFactory
|
|
62 |
*/
|
|
63 |
public class TestEventFactory {
|
|
64 |
|
|
65 |
@MetadataDefinition
|
|
66 |
@Retention(RetentionPolicy.RUNTIME)
|
|
67 |
@Target({ ElementType.FIELD, ElementType.TYPE })
|
|
68 |
public @interface TestAnnotation {
|
|
69 |
String value();
|
|
70 |
}
|
|
71 |
|
|
72 |
public final static Map<String, Object> EVENT_VALUES = new HashMap<>();
|
|
73 |
public final static EventTypePrototype EVENT_TYPE_SHOULD_NOT_COMMIT;
|
|
74 |
public final static EventTypePrototype EVENT_TYPE_SHOULD_COMMIT;
|
|
75 |
|
|
76 |
// keep alive to prevent event metadata getting GC.
|
|
77 |
public static EventFactory ef1;
|
|
78 |
public static EventFactory ef2;
|
|
79 |
|
|
80 |
static {
|
|
81 |
EVENT_VALUES.put("intField", Integer.MAX_VALUE);
|
|
82 |
EVENT_VALUES.put("longField", Long.MAX_VALUE);
|
|
83 |
EVENT_VALUES.put("byteField", (byte) 5);
|
|
84 |
EVENT_VALUES.put("charField", (char) 'H');
|
|
85 |
EVENT_VALUES.put("shortField", (short) 56);
|
|
86 |
EVENT_VALUES.put("booleanField", true);
|
|
87 |
EVENT_VALUES.put("floatField", 4711.0f);
|
|
88 |
EVENT_VALUES.put("doubleField", 3.141);
|
|
89 |
EVENT_VALUES.put("classField", String.class);
|
|
90 |
EVENT_VALUES.put("stringField", "Yeah!");
|
|
91 |
EVENT_VALUES.put("threadField", Thread.currentThread());
|
|
92 |
|
|
93 |
EVENT_TYPE_SHOULD_NOT_COMMIT = makeEventType("com.test.ShouldNotCommit");
|
|
94 |
EVENT_TYPE_SHOULD_COMMIT = makeEventType("com.test.ShouldCommit");
|
|
95 |
}
|
|
96 |
|
|
97 |
public static void main(String[] args) throws Throwable {
|
|
98 |
Recording r = new Recording();
|
|
99 |
r.enable(EVENT_TYPE_SHOULD_COMMIT.getName()).withoutStackTrace();
|
|
100 |
r.enable(EVENT_TYPE_SHOULD_NOT_COMMIT.getName()).withoutStackTrace();
|
|
101 |
|
|
102 |
// Commit before start, should not be included
|
|
103 |
ef1 = EventFactory.create(EVENT_TYPE_SHOULD_NOT_COMMIT.getAnnotations(), EVENT_TYPE_SHOULD_NOT_COMMIT.getFields());
|
|
104 |
|
|
105 |
Event event1 = ef1.newEvent();
|
|
106 |
|
|
107 |
setEventValues(event1, ef1, EVENT_TYPE_SHOULD_NOT_COMMIT);
|
|
108 |
event1.commit();
|
|
109 |
|
|
110 |
r.start();
|
|
111 |
// Commit after start, should be included
|
|
112 |
ef2 = EventFactory.create(EVENT_TYPE_SHOULD_COMMIT.getAnnotations(), EVENT_TYPE_SHOULD_COMMIT.getFields());
|
|
113 |
|
|
114 |
Event event2 = ef2.newEvent();
|
|
115 |
setEventValues(event2, ef2, EVENT_TYPE_SHOULD_COMMIT);
|
|
116 |
event2.commit();
|
|
117 |
|
|
118 |
r.stop();
|
|
119 |
|
|
120 |
RecordingFile es = Events.copyTo(r);
|
|
121 |
EventType e1 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_NOT_COMMIT.getName());
|
|
122 |
assertEquals(e1, ef1.getEventType());
|
|
123 |
|
|
124 |
EventType e2 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_COMMIT.getName());
|
|
125 |
assertEquals(e2, ef2.getEventType());
|
|
126 |
|
|
127 |
verifyEvent(es);
|
|
128 |
}
|
|
129 |
|
|
130 |
private static EventType findEventType(List<EventType> es, String name) {
|
|
131 |
for (EventType t : es) {
|
|
132 |
if (t.getName().equals(name)) {
|
|
133 |
return t;
|
|
134 |
}
|
|
135 |
}
|
|
136 |
throw new AssertionError("Could not find expected event type " + name);
|
|
137 |
}
|
|
138 |
|
|
139 |
private static void assertEquals(EventType e1, EventType expected) {
|
|
140 |
Asserts.assertEquals(e1.getName(), expected.getName());
|
|
141 |
Asserts.assertEquals(e1.getDescription(), expected.getDescription());
|
|
142 |
Asserts.assertEquals(e1.getLabel(), expected.getLabel());
|
|
143 |
assertValueDescriptorEquals(e1.getFields(), expected.getFields());
|
|
144 |
assertAnnotationEquals(e1.getAnnotationElements(), expected.getAnnotationElements());
|
|
145 |
}
|
|
146 |
|
|
147 |
private static void assertValueDescriptorEquals(List<ValueDescriptor> values, List<ValueDescriptor> expected) {
|
|
148 |
if (values.isEmpty() && expected.isEmpty()) {
|
|
149 |
return;
|
|
150 |
}
|
|
151 |
|
|
152 |
Map<String, ValueDescriptor> valueMap = new HashMap<>();
|
|
153 |
for (ValueDescriptor v : values) {
|
|
154 |
valueMap.put(v.getName(), v);
|
|
155 |
}
|
|
156 |
for (ValueDescriptor f : expected) {
|
|
157 |
ValueDescriptor v = valueMap.remove(f.getName());
|
|
158 |
if (v == null) {
|
|
159 |
throw new AssertionError("Expected value descriptor " + f.getName() + " not found");
|
|
160 |
}
|
|
161 |
assertEquals(v, f);
|
|
162 |
}
|
|
163 |
if (!valueMap.isEmpty()) {
|
|
164 |
throw new AssertionError("More fields than expected");
|
|
165 |
}
|
|
166 |
}
|
|
167 |
|
|
168 |
private static void assertEquals(ValueDescriptor v1, ValueDescriptor expected) {
|
|
169 |
Asserts.assertEquals(v1.getName(), expected.getName());
|
|
170 |
Asserts.assertEquals(v1.getTypeName(), expected.getTypeName());
|
|
171 |
assertAnnotationEquals(v1.getAnnotationElements(), expected.getAnnotationElements());
|
|
172 |
}
|
|
173 |
|
|
174 |
private static void assertAnnotationEquals(List<AnnotationElement> annotations, List<AnnotationElement> expected) {
|
|
175 |
annotations = new ArrayList<>(annotations); // make mutable
|
|
176 |
expected = new ArrayList<>(expected); // make mutable
|
|
177 |
class AnnotationTypeComparator implements Comparator<AnnotationElement> {
|
|
178 |
@Override
|
|
179 |
public int compare(AnnotationElement a, AnnotationElement b) {
|
|
180 |
return a.getTypeName().compareTo(b.getTypeName());
|
|
181 |
}
|
|
182 |
}
|
|
183 |
|
|
184 |
if (annotations.isEmpty() && expected.isEmpty()) {
|
|
185 |
return;
|
|
186 |
}
|
|
187 |
|
|
188 |
if (annotations.size() != expected.size()) {
|
|
189 |
System.out.println("Was:");
|
|
190 |
for(AnnotationElement ae: annotations) {
|
|
191 |
System.out.println(ae.getTypeName());
|
|
192 |
}
|
|
193 |
System.out.println("Expected:");
|
|
194 |
for(AnnotationElement ae: expected) {
|
|
195 |
System.out.println(ae.getTypeName());
|
|
196 |
}
|
|
197 |
throw new AssertionError("Wrong number of annotations");
|
|
198 |
}
|
|
199 |
Collections.sort(expected, new AnnotationTypeComparator());
|
|
200 |
Collections.sort(annotations, new AnnotationTypeComparator());
|
|
201 |
for (int i = 0; i < expected.size(); i++) {
|
|
202 |
assertEquals(annotations.get(i), expected.get(i));
|
|
203 |
}
|
|
204 |
}
|
|
205 |
|
|
206 |
private static void assertEquals(AnnotationElement a1, AnnotationElement expected) {
|
|
207 |
Asserts.assertEquals(a1.getTypeName(), expected.getTypeName());
|
|
208 |
// Don't recurse into annotation
|
|
209 |
assertValueDescriptorEquals(a1.getValueDescriptors(), expected.getValueDescriptors());
|
|
210 |
}
|
|
211 |
|
|
212 |
private static void verifyEvent(RecordingFile rf) throws IOException {
|
|
213 |
if (!rf.hasMoreEvents()) {
|
|
214 |
throw new AssertionError("Expected one dynamic event");
|
|
215 |
}
|
|
216 |
verifyValues(rf.readEvent());
|
|
217 |
if (rf.hasMoreEvents()) {
|
|
218 |
throw new AssertionError("Expected one dynamic event");
|
|
219 |
}
|
|
220 |
}
|
|
221 |
|
|
222 |
private static void setEventValues(Event event, EventFactory f, EventTypePrototype eventTypeProto) {
|
|
223 |
for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
|
|
224 |
int index = eventTypeProto.getFieldIndex(entry.getKey());
|
|
225 |
event.set(index, entry.getValue());
|
|
226 |
}
|
|
227 |
}
|
|
228 |
|
|
229 |
private static void verifyValues(RecordedEvent event) {
|
|
230 |
for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
|
|
231 |
String fieldName = entry.getKey();
|
|
232 |
Object value = event.getValue(fieldName);
|
|
233 |
Object expected = EVENT_VALUES.get(fieldName);
|
|
234 |
if (expected instanceof Class) {
|
|
235 |
value = ((RecordedClass) value).getName();
|
|
236 |
expected = ((Class<?>) expected).getName();
|
|
237 |
}
|
|
238 |
if (expected instanceof Thread) {
|
|
239 |
value = ((RecordedThread) value).getJavaName();
|
|
240 |
expected = ((Thread) expected).getName();
|
|
241 |
}
|
|
242 |
Asserts.assertEQ(value, expected);
|
|
243 |
}
|
|
244 |
}
|
|
245 |
|
|
246 |
private static EventTypePrototype makeEventType(String eventName) {
|
|
247 |
EventTypePrototype prototype = new EventTypePrototype(eventName);
|
|
248 |
prototype.addAnnotation(new AnnotationElement(TestAnnotation.class, "type"));
|
|
249 |
for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
|
|
250 |
Class<?> type = makePrimitive(entry.getValue().getClass());
|
|
251 |
String fieldName = entry.getKey();
|
|
252 |
prototype.addField(new ValueDescriptor(type, fieldName));
|
|
253 |
}
|
|
254 |
// add an annotated field
|
|
255 |
List<AnnotationElement> annos = new ArrayList<>();
|
|
256 |
annos.add(new AnnotationElement(TestAnnotation.class, "field"));
|
|
257 |
prototype.addField( new ValueDescriptor(int.class, "annotatedField", annos));
|
|
258 |
|
|
259 |
return prototype;
|
|
260 |
}
|
|
261 |
|
|
262 |
private static Class<?> makePrimitive(Class<? extends Object> clazz) {
|
|
263 |
if (clazz == Integer.class) {
|
|
264 |
return int.class;
|
|
265 |
}
|
|
266 |
if (clazz == Long.class) {
|
|
267 |
return long.class;
|
|
268 |
}
|
|
269 |
if (clazz == Double.class) {
|
|
270 |
return double.class;
|
|
271 |
}
|
|
272 |
if (clazz == Float.class) {
|
|
273 |
return float.class;
|
|
274 |
}
|
|
275 |
if (clazz == Short.class) {
|
|
276 |
return short.class;
|
|
277 |
}
|
|
278 |
if (clazz == Character.class) {
|
|
279 |
return char.class;
|
|
280 |
}
|
|
281 |
if (clazz == Byte.class) {
|
|
282 |
return byte.class;
|
|
283 |
}
|
|
284 |
if (clazz == Boolean.class) {
|
|
285 |
return boolean.class;
|
|
286 |
}
|
|
287 |
return clazz;
|
|
288 |
}
|
|
289 |
}
|