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