1 /* 2 * Copyright (c) 2016, 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.internal; 27 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.Objects; 34 35 import jdk.jfr.AnnotationElement; 36 import jdk.jfr.Event; 37 import jdk.jfr.SettingControl; 38 import jdk.jfr.ValueDescriptor; 39 40 /** 41 * Internal data structure that describes a type, 42 * 43 * Used to create event types, value descriptor and annotations. 44 * 45 */ 46 public class Type implements Comparable<Type> { 47 public static final String SUPER_TYPE_ANNOTATION = java.lang.annotation.Annotation.class.getName(); 48 public static final String SUPER_TYPE_SETTING = SettingControl.class.getName(); 49 public static final String SUPER_TYPE_EVENT = Event.class.getName(); 50 public static final String ORACLE_EVENT_PREFIX = "com.oracle.jdk."; 51 public static final String ORACLE_TYPE_PREFIX = "com.oracle.jfr.types."; 52 53 // Initialization of known types 54 private final static Map<Type, Class<?>> knownTypes = new HashMap<>(); 55 static final Type BOOLEAN = register(boolean.class, new Type("boolean", null, 4)); 56 static final Type CHAR = register(char.class, new Type("char", null, 5)); 57 static final Type FLOAT = register(float.class, new Type("float", null, 6)); 58 static final Type DOUBLE = register(double.class, new Type("double", null, 7)); 59 static final Type BYTE = register(byte.class, new Type("byte", null, 8)); 60 static final Type SHORT = register(short.class, new Type("short", null, 9)); 61 static final Type INT = register(int.class, new Type("int", null, 10)); 62 static final Type LONG = register(long.class, new Type("long", null, 11)); 63 static final Type CLASS = register(Class.class, new Type("java.lang.Class", null, 20)); 64 static final Type STRING = register(String.class, new Type("java.lang.String", null, 21)); 65 static final Type THREAD = register(Thread.class, new Type("java.lang.Thread", null, 22)); 66 static final Type STACK_TRACE = register(null, new Type(ORACLE_TYPE_PREFIX + "StackTrace", null, 23)); 67 68 private final AnnotationConstruct annos = new AnnotationConstruct(); 69 private final String name; 70 private final String superType; 71 private final boolean constantPool; 72 private final long id; 73 private final ArrayList<ValueDescriptor> fields = new ArrayList<>(); 74 private Boolean simpleType; // calculated lazy 75 private boolean remove = true; 76 /** 77 * Creates a type 78 * 79 * @param javaTypeName i.e "com.oracle.jfr.type.StackFrame" 80 * @param superType i.e "com.oracle.jfr.Event" and "java.lang.Annotation" 81 * @param id the class id that represents the class in the JVM 82 * 83 */ 84 public Type(String javaTypeName, String superType, long typeId) { 85 this(javaTypeName, superType, typeId, false); 86 } 87 88 Type(String javaTypeName, String superType, long typeId, boolean contantPool) { 89 this(javaTypeName, superType, typeId, contantPool, null); 90 } 91 92 Type(String javaTypeName, String superType, long typeId, boolean contantPool, Boolean simpleType) { 93 Objects.requireNonNull(javaTypeName); 94 95 if (!isValidJavaIdentifier(javaTypeName)) { 96 throw new IllegalArgumentException(javaTypeName + " is not a valid Java identifier"); 97 } 98 this.constantPool = contantPool; 99 this.superType = superType; 100 this.name = javaTypeName; 101 this.id = typeId; 102 this.simpleType = simpleType; 103 } 104 105 static boolean isDefinedByJVM(long id) { 106 return id < JVM.RESERVED_CLASS_ID_LIMIT; 107 } 108 109 public static long getTypeId(Class<?> clazz) { 110 Type type = Type.getKnownType(clazz); 111 return type == null ? JVM.getJVM().getTypeId(clazz) : type.getId(); 112 } 113 114 static Collection<Type> getKnownTypes() { 115 return knownTypes.keySet(); 116 } 117 118 public static boolean isValidJavaIdentifier(String identifier) { 119 if (identifier.isEmpty()) { 120 return false; 121 } 122 if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { 123 return false; 124 } 125 for (int i = 1; i < identifier.length(); i++) { 126 char c = identifier.charAt(i); 127 if (c != '.') { 128 if (!Character.isJavaIdentifierPart(c)) { 129 return false; 130 } 131 } 132 } 133 return true; 134 } 135 136 public static boolean isValidJavaFieldType(String name) { 137 for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) { 138 Class<?> clazz = entry.getValue(); 139 if (clazz != null && name.equals(clazz.getName())) { 140 return true; 141 } 142 } 143 return false; 144 } 145 146 public static Class<?> getKnownType(String className) { 147 for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) { 148 Class<?> clazz = entry.getValue(); 149 if (clazz != null) { 150 String knownClassName = clazz.getName(); 151 if (className.equals(knownClassName)) { 152 return clazz; 153 } 154 } 155 } 156 return null; 157 } 158 159 static boolean isKnownType(Class<?> type) { 160 if (type.isPrimitive()) { 161 return true; 162 } 163 if (type.equals(Class.class) || type.equals(Thread.class) || type.equals(String.class)) { 164 return true; 165 } 166 return false; 167 } 168 169 public static Type getKnownType(Class<?> clazz) { 170 for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) { 171 if (clazz != null && clazz.equals(entry.getValue())) { 172 return entry.getKey(); 173 } 174 } 175 return null; 176 } 177 178 public String getName() { 179 return name; 180 } 181 182 public String getLogName() { 183 return getName() + "(" + getId() + ")"; 184 } 185 186 public List<ValueDescriptor> getFields() { 187 return fields; 188 } 189 190 public boolean isSimpleType() { 191 if (simpleType == null) { 192 simpleType = calculateSimpleType(); 193 } 194 return simpleType.booleanValue(); 195 } 196 197 private boolean calculateSimpleType() { 198 if (fields.size() != 1) { 199 return false; 200 } 201 // annotation, settings and event can never be simple types 202 return superType == null; 203 } 204 205 public boolean isDefinedByJVM() { 206 return id < JVM.RESERVED_CLASS_ID_LIMIT; 207 } 208 209 private static Type register(Class<?> clazz, Type type) { 210 knownTypes.put(type, clazz); 211 return type; 212 } 213 214 public void add(ValueDescriptor valueDescriptor) { 215 Objects.requireNonNull(valueDescriptor); 216 fields.add(valueDescriptor); 217 } 218 219 void trimFields() { 220 fields.trimToSize(); 221 } 222 223 void setAnnotations(List<AnnotationElement> annotations) { 224 annos.setAnnotationElements(annotations); 225 } 226 227 public String getSuperType() { 228 return superType; 229 } 230 231 public long getId() { 232 return id; 233 } 234 235 public boolean isConstantPool() { 236 return constantPool; 237 } 238 239 public String getLabel() { 240 return annos.getLabel(); 241 } 242 243 public List<AnnotationElement> getAnnotationElements() { 244 return annos.getUnmodifiableAnnotationElements(); 245 } 246 247 public <T> T getAnnotation(Class<? extends java.lang.annotation.Annotation> clazz) { 248 return annos.getAnnotation(clazz); 249 } 250 251 public String getDescription() { 252 return annos.getDescription(); 253 } 254 255 @Override 256 public int hashCode() { 257 return Long.hashCode(id); 258 } 259 260 @Override 261 public boolean equals(Object object) { 262 if (object instanceof Type) { 263 Type that = (Type) object; 264 return that.id == this.id; 265 } 266 return false; 267 } 268 269 @Override 270 public int compareTo(Type that) { 271 return Long.compare(this.id, that.id); 272 } 273 274 void log(String action, LogTag logTag, LogLevel level) { 275 if (logTag.shouldLog(level.level) && !isSimpleType()) { 276 Logger.log(logTag, LogLevel.TRACE, action + " " + typeText() + " " + getLogName() + " {"); 277 for (ValueDescriptor v : getFields()) { 278 String array = v.isArray() ? "[]" : ""; 279 Logger.log(logTag, LogLevel.TRACE, " " + v.getTypeName() + array + " " + v.getName() + ";"); 280 } 281 Logger.log(logTag, LogLevel.TRACE, "}"); 282 } else { 283 if (logTag.shouldLog(LogLevel.INFO.level) && !isSimpleType()) { 284 Logger.log(logTag, LogLevel.INFO, action + " " + typeText() + " " + getLogName()); 285 } 286 } 287 } 288 289 private String typeText() { 290 if (this instanceof PlatformEventType) { 291 return "event type"; 292 } 293 if (Type.SUPER_TYPE_SETTING.equals(superType)) { 294 return "setting type"; 295 } 296 if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) { 297 return "annotation type"; 298 } 299 return "type"; 300 } 301 302 @Override 303 public String toString() { 304 StringBuilder sb = new StringBuilder(); 305 sb.append(getLogName()); 306 if (!getFields().isEmpty()) { 307 sb.append(" {\n"); 308 for (ValueDescriptor td : getFields()) { 309 sb.append(" type=" + td.getTypeName() + "(" + td.getTypeId() + ") name=" + td.getName() + "\n"); 310 } 311 sb.append("}\n"); 312 } 313 return sb.toString(); 314 } 315 316 public void setRemove(boolean remove) { 317 this.remove = remove; 318 } 319 320 public boolean getRemove() { 321 return remove; 322 } 323 }