diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
index 2b04b433c29f2..644abcc324c5a 100644
--- a/src/hotspot/share/jfr/metadata/metadata.xml
+++ b/src/hotspot/share/jfr/metadata/metadata.xml
@@ -453,10 +453,10 @@
-
-
-
-
+
+
+
+
-
+
@@ -1007,7 +1007,7 @@
-
+
@@ -1030,10 +1030,10 @@
-
+
-
-
+
+
diff --git a/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java b/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java
index e3255909fccb7..78a92d9a2d9ad 100644
--- a/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java
+++ b/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java
@@ -23,6 +23,7 @@
package jdk.jfr.event.metadata;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -51,7 +52,7 @@ public class TestEventMetadata {
* ----
*
* Symbolic name that is used to identify an event, or a field. Referred to
- * as "id" and "field" in trace.xml-files and @Name in the Java API. If it is
+ * as "name" in metadata.xml and @Name in the Java API. If it is
* the name of an event, the name should be prefixed "jdk.", which
* happens automatically for native events.
*
@@ -61,10 +62,10 @@ public class TestEventMetadata {
* "allocationRate" for a field. Do not use "_" and don't add the word
* "Event" to the event name.
*
- * Abbreviations should be avoided, but may be acceptable if the name
- * becomes long, or if it is a well established acronym. Write whole words,
- * i.e. "allocation" instead of "alloc". The name should not be a reserved
- * Java keyword, i.e "void" or "class".
+ * Abbreviations, such as info, alloc, num, gen, conf, stat, and evac, should
+ * be avoided. For example, use "allocation" instead of "alloc". Acronyms should be
+ * avoided unless they are well-established. The name should not be a reserved
+ * Java keyword, such as "void" or "class".
*
* Label
* -----
@@ -84,8 +85,8 @@ public class TestEventMetadata {
* period should not be included.
*
*
- * Do not forget to set proper units for fields, i.e "NANOS", "MILLS",
- * "TICKSPAN" ,"BYETS", "PECENTAGE" etc. in native and @Timespan, @Timespan
+ * Do not forget to set proper units for fields, such as "NANOS", "MILLIS",
+ * "TICKSPAN", "BYTES", and "PERCENTAGE", in native and @Timespan, @Timespan
* etc. in Java.
*/
public static void main(String[] args) throws Exception {
@@ -161,18 +162,63 @@ private static void verifyName(String name) {
}
private static void verifyLabel(String label) {
+ System.out.println("Verifying label: " + label);
Asserts.assertNotEquals(label, null, "Label not allowed to be null");
- Asserts.assertTrue(label.length() > 1, "Name must be at least two characters");
- Asserts.assertTrue(label.length() < 45, "Label should not exceed 45 characters, use description to explain " + label);
- Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have trim character at start and end");
- Asserts.assertTrue(Character.isUpperCase(label.charAt(0)), "Label should start with upper case letter");
- for (int i = 0; i < label.length(); i++) {
- char c = label.charAt(i);
- 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)
- + "'");
+ Asserts.assertTrue(label.length() > 1, "Label must be at least two characters");
+ Asserts.assertTrue(label.length() <= 45, "Label should not exceed 45 characters, use description to explain");
+ Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have superfluous whitespace at start or end");
+
+ String[] words = label.split(" ");
+ String[] middleWords = words.length > 2 ? Arrays.copyOfRange(words, 1, words.length - 1) : new String[0];
+ String firstWord = words[0];
+ String lastWord = words[words.length - 1];
+ Asserts.assertTrue(isCapitalized(firstWord), "Label should capitalize first word");
+
+ // The isNumeric check is a workaround so "GC Phase Pause Level 1" doesn't fail.
+ if (!isNumeric(lastWord)) {
+ Asserts.assertTrue(isCapitalized(lastWord), "Label should capitalize last word");
+ }
+ for (String word : words) {
+ Asserts.assertFalse(word.endsWith("-") || word.startsWith("-"), "Word in label should not start or end with hyphen");
+ Asserts.assertTrue(word.length() != 0, "Label should not contain superfluous whitespace");
+ if (isCapitalized(word)) {
+ for (String w : word.split("-")) {
+ Asserts.assertTrue(isCapitalized(w), "Label should capitalize all words in a hyphenated word");
+ }
+ }
+ }
+ for (String word : middleWords) {
+ if (isShortCommonPreposition(word)) {
+ Asserts.assertFalse(isCapitalized(word), "Preposition in label should be lower case, unless first and last word");
+ }
+ }
+ for (char c : label.toCharArray()) {
+ Asserts.assertTrue(isAllowedCharacter(c), "Label should only consist of letters, numbers, hyphens, parentheses or whitespace, found '" + c + "'");
}
}
+ private static boolean isAllowedCharacter(char c) {
+ return Character.isDigit(c) || Character.isAlphabetic(c) || c == ' ' || c == '(' || c == ')' || c == '-';
+ }
+
+ private static boolean isCapitalized(String word) {
+ String w = word.replace("(", "").replace(")", "");
+ return !w.isEmpty() && Character.isUpperCase(w.charAt(0));
+ }
+
+ private static boolean isNumeric(String word) {
+ return word.chars().allMatch(Character::isDigit);
+ }
+
+ private static boolean isShortCommonPreposition(String word) {
+ String[] prepositions = { "in", "on", "at", "by", "to", "of" };
+ return containsWord(prepositions, word);
+ }
+
+ private static boolean containsWord(String[] words, String match) {
+ return Arrays.asList(words).contains(match);
+ }
+
private static void verifyEventType(EventType eventType) {
System.out.println("Verifying event: " + eventType.getName());
verifyDescription(eventType.getDescription());
@@ -182,7 +228,7 @@ private static void verifyEventType(EventType eventType) {
String name = eventType.getName().substring(EventNames.PREFIX.length());
Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")");
checkCommonAbbreviations(name);
- char firstChar = name.charAt(0);
+ char firstChar = name.charAt(0);
Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'");
Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name " + name + " must start with a character");
Asserts.assertTrue(Character.isUpperCase(firstChar), "Name " + name + " must start with upper case letter");
@@ -198,12 +244,7 @@ static boolean isReservedKeyword(String s) {
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum",
"extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private",
"protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" };
- for (int i = 0; i < keywords.length; i++) {
- if (s.equals(keywords[i])) {
- return true;
- }
- }
- return false;
+ return containsWord(keywords, s);
}
private static void checkCommonAbbreviations(String name) {