50113
|
1 |
/*
|
|
2 |
* Copyright (c) 2013, 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.event.metadata;
|
|
27 |
|
|
28 |
import java.util.HashSet;
|
|
29 |
import java.util.List;
|
|
30 |
import java.util.Set;
|
|
31 |
|
|
32 |
import jdk.jfr.EventType;
|
|
33 |
import jdk.jfr.FlightRecorder;
|
|
34 |
import jdk.jfr.ValueDescriptor;
|
|
35 |
import jdk.test.lib.Asserts;
|
|
36 |
import jdk.test.lib.jfr.EventNames;
|
|
37 |
|
|
38 |
/*
|
|
39 |
* @test
|
|
40 |
* @key jfr
|
|
41 |
* @library /test/lib
|
|
42 |
* @run main/othervm jdk.jfr.event.metadata.TestEventMetadata
|
|
43 |
*/
|
|
44 |
|
|
45 |
public class TestEventMetadata {
|
|
46 |
|
|
47 |
/*
|
|
48 |
* Short guide to writing event metadata
|
|
49 |
* =====================================
|
|
50 |
|
|
51 |
* Name
|
|
52 |
* ----
|
|
53 |
*
|
|
54 |
* Symbolic name that is used to identify an event, or a field. Referred to
|
|
55 |
* as "id" and "field" in trace.xml-files and @Name in the Java API. If it is
|
|
56 |
* the name of an event, the name should be prefixed "jdk.", which
|
|
57 |
* happens automatically for native events.
|
|
58 |
*
|
|
59 |
* The name should be short, but not so brief that collision is likely with
|
|
60 |
* future events or fields. It should only consist of letters and numbers.
|
|
61 |
* Use Java naming convention , i.e. "FileRead" for an event and
|
|
62 |
* "allocationRate" for a field. Do not use "_" and don't add the word
|
|
63 |
* "Event" to the event name.
|
|
64 |
*
|
|
65 |
* Abbreviations should be avoided, but may be acceptable if the name
|
|
66 |
* becomes long, or if it is a well established acronym. Write whole words,
|
|
67 |
* i.e. "allocation" instead of "alloc". The name should not be a reserved
|
|
68 |
* Java keyword, i.e "void" or "class".
|
|
69 |
*
|
|
70 |
* Label
|
|
71 |
* -----
|
|
72 |
*
|
|
73 |
* Describes a human-readable name, typically 1-3 words. Use headline-style
|
|
74 |
* capitalization, capitalize the first and last words, and all nouns,
|
|
75 |
* pronouns, adjectives, verbs and adverbs. Do not include ending
|
|
76 |
* punctuation.
|
|
77 |
*
|
|
78 |
* Description
|
|
79 |
* -----------
|
|
80 |
*
|
|
81 |
* Describes an event with a sentence or two. It's better to omit the
|
|
82 |
* description then copying the label. Use sentence-style
|
|
83 |
* capitalization, capitalize the first letter of the first word, and any
|
|
84 |
* proper names such as the word Java. If the description is one sentence,
|
|
85 |
* period should not be included.
|
|
86 |
*
|
|
87 |
*
|
|
88 |
* Do not forget to set proper units for fields, i.e "NANOS", "MILLS",
|
|
89 |
* "TICKSPAN" ,"BYETS", "PECENTAGE" etc. in native and @Timespan, @Timespan
|
|
90 |
* etc. in Java.
|
|
91 |
*/
|
|
92 |
public static void main(String[] args) throws Exception {
|
|
93 |
Set<String> types = new HashSet<>();
|
|
94 |
List<EventType> eventTypes = FlightRecorder.getFlightRecorder().getEventTypes();
|
|
95 |
Set<String> eventNames= new HashSet<>();
|
|
96 |
for (EventType eventType : eventTypes) {
|
|
97 |
verifyEventType(eventType);
|
|
98 |
verifyValueDesscriptors(eventType.getFields(), types);
|
|
99 |
System.out.println();
|
|
100 |
String eventName = eventType.getName();
|
|
101 |
if (eventNames.contains(eventName)) {
|
|
102 |
throw new Exception("Event with name " +eventName+ " already exists");
|
|
103 |
}
|
|
104 |
eventNames.add(eventName);
|
|
105 |
Set<String> fieldNames = new HashSet<>();
|
|
106 |
for (ValueDescriptor v : eventType.getFields()) {
|
|
107 |
String fieldName = v.getName();
|
|
108 |
if (fieldNames.contains(fieldName)) {
|
|
109 |
throw new Exception("Field with name " + fieldName +" is already in use in event name " +eventName);
|
|
110 |
}
|
|
111 |
fieldNames.add(fieldName);
|
|
112 |
}
|
|
113 |
}
|
|
114 |
}
|
|
115 |
|
|
116 |
private static void verifyValueDesscriptors(List<ValueDescriptor> fields, Set<String> visitedTypes) {
|
|
117 |
for (ValueDescriptor v : fields) {
|
|
118 |
if (!visitedTypes.contains(v.getTypeName())) {
|
|
119 |
visitedTypes.add(v.getTypeName());
|
|
120 |
verifyValueDesscriptors(v.getFields(), visitedTypes);
|
|
121 |
}
|
|
122 |
verifyValueDescriptor(v);
|
|
123 |
}
|
|
124 |
}
|
|
125 |
|
|
126 |
private static void verifyValueDescriptor(ValueDescriptor v) {
|
|
127 |
verifyName(v.getName());
|
|
128 |
verifyLabel(v.getLabel());
|
|
129 |
verifyDescription(v.getDescription());
|
|
130 |
}
|
|
131 |
|
|
132 |
private static void verifyDescription(String description) {
|
|
133 |
if (description == null) {
|
|
134 |
return;
|
|
135 |
}
|
|
136 |
Asserts.assertTrue(description.length() > 10, "Description must be at least ten characters");
|
|
137 |
Asserts.assertTrue(description.length() < 300, "Description should not exceed 300 characters. Found " + description);
|
|
138 |
Asserts.assertTrue(description.length() == description.trim().length(), "Description should not have trim character at start or end");
|
|
139 |
Asserts.assertFalse(description.endsWith(".") && description.indexOf(".") == description.length() - 1, "Single sentence descriptions should not use end punctuation");
|
|
140 |
}
|
|
141 |
|
|
142 |
private static void verifyName(String name) {
|
|
143 |
System.out.println("Verifying name: " + name);
|
|
144 |
Asserts.assertNotEquals(name, null, "Name not allowed to be null");
|
|
145 |
Asserts.assertTrue(name.length() > 1, "Name must be at least two characters");
|
|
146 |
Asserts.assertTrue(name.length() < 32, "Name should not exceed 32 characters");
|
|
147 |
Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")");
|
|
148 |
char firstChar = name.charAt(0);
|
|
149 |
Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name must start with a character");
|
|
150 |
Asserts.assertTrue(Character.isLowerCase(firstChar), "Name must start with lower case letter");
|
|
151 |
Asserts.assertTrue(Character.isJavaIdentifierStart(firstChar), "Not valid first character for Java identifier");
|
|
152 |
for (int i = 1; i < name.length(); i++) {
|
|
153 |
Asserts.assertTrue(Character.isJavaIdentifierPart(name.charAt(i)), "Not valid character for a Java identifier");
|
|
154 |
Asserts.assertTrue(Character.isAlphabetic(name.charAt(i)), "Name must consists of characters, found '" + name.charAt(i) + "'");
|
|
155 |
}
|
|
156 |
Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'");
|
|
157 |
checkCommonAbbreviations(name);
|
|
158 |
}
|
|
159 |
|
|
160 |
private static void verifyLabel(String label) {
|
|
161 |
Asserts.assertNotEquals(label, null, "Label not allowed to be null");
|
|
162 |
Asserts.assertTrue(label.length() > 1, "Name must be at least two characters");
|
|
163 |
Asserts.assertTrue(label.length() < 45, "Label should not exceed 45 characters, use description to explain " + label);
|
|
164 |
Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have trim character at start and end");
|
|
165 |
Asserts.assertTrue(Character.isUpperCase(label.charAt(0)), "Label should start with upper case letter");
|
|
166 |
for (int i = 0; i < label.length(); i++) {
|
|
167 |
char c = label.charAt(i);
|
|
168 |
Asserts.assertTrue(Character.isDigit(c) || Character.isAlphabetic(label.charAt(i)) || c == ' ' || c == '(' || c == ')' || c == '-', "Label should only consist of letters or space, found '" + label.charAt(i)
|
|
169 |
+ "'");
|
|
170 |
}
|
|
171 |
}
|
|
172 |
|
|
173 |
private static void verifyEventType(EventType eventType) {
|
|
174 |
System.out.println("Verifying event: " + eventType.getName());
|
|
175 |
verifyDescription(eventType.getDescription());
|
|
176 |
verifyLabel(eventType.getLabel());
|
|
177 |
Asserts.assertNotEquals(eventType.getName(), null, "Name not allowed to be null");
|
|
178 |
Asserts.assertTrue(eventType.getName().startsWith(EventNames.PREFIX), "OpenJDK events must start with " + EventNames.PREFIX);
|
|
179 |
String name = eventType.getName().substring(EventNames.PREFIX.length());
|
|
180 |
Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")");
|
|
181 |
checkCommonAbbreviations(name);
|
|
182 |
char firstChar = name.charAt(0);
|
|
183 |
Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'");
|
|
184 |
Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name " + name + " must start with a character");
|
|
185 |
Asserts.assertTrue(Character.isUpperCase(firstChar), "Name " + name + " must start with upper case letter");
|
|
186 |
for (int i = 0; i < name.length(); i++) {
|
|
187 |
char c = name.charAt(i);
|
|
188 |
Asserts.assertTrue(Character.isAlphabetic(c) || Character.isDigit(c), "Name " + name + " must consists of characters or numbers, found '" + name.charAt(i) + "'");
|
|
189 |
}
|
|
190 |
}
|
|
191 |
|
|
192 |
static boolean isReservedKeyword(String s) {
|
|
193 |
String[] keywords = new String[] {
|
|
194 |
// "module", "requires", "exports", "to", "uses", "provides", "with", module-info.java
|
|
195 |
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum",
|
|
196 |
"extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private",
|
|
197 |
"protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" };
|
|
198 |
for (int i = 0; i < keywords.length; i++) {
|
|
199 |
if (s.equals(keywords[i])) {
|
|
200 |
return true;
|
|
201 |
}
|
|
202 |
}
|
|
203 |
return false;
|
|
204 |
}
|
|
205 |
|
|
206 |
private static void checkCommonAbbreviations(String name) {
|
|
207 |
String lowerCased = name.toLowerCase();
|
|
208 |
Asserts.assertFalse(lowerCased.contains("info") && !lowerCased.contains("information"), "Use 'information' instead 'info' in name");
|
|
209 |
Asserts.assertFalse(lowerCased.contains("alloc") && !lowerCased.contains("alloca"), "Use 'allocation' instead 'alloc' in name");
|
|
210 |
Asserts.assertFalse(lowerCased.contains("config") && !lowerCased.contains("configuration"), "Use 'configuration' instead of 'config' in name");
|
|
211 |
Asserts.assertFalse(lowerCased.contains("evac") && !lowerCased.contains("evacu"), "Use 'evacuation' instead of 'evac' in name");
|
|
212 |
Asserts.assertFalse(lowerCased.contains("stat") && !(lowerCased.contains("state") ||lowerCased.contains("statistic")) , "Use 'statistics' instead of 'stat' in name");
|
|
213 |
Asserts.assertFalse(name.contains("ID") , "Use 'id' or 'Id' instead of 'ID' in name");
|
|
214 |
}
|
|
215 |
}
|