/*
 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.jfr.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import jdk.jfr.AnnotationElement;
import jdk.jfr.Event;
import jdk.jfr.SettingControl;
import jdk.jfr.ValueDescriptor;

Internal data structure that describes a type, Used to create event types, value descriptor and annotations.
/** * Internal data structure that describes a type, * * Used to create event types, value descriptor and annotations. * */
public class Type implements Comparable<Type> { public static final String SUPER_TYPE_ANNOTATION = java.lang.annotation.Annotation.class.getName(); public static final String SUPER_TYPE_SETTING = SettingControl.class.getName(); public static final String SUPER_TYPE_EVENT = Event.class.getName(); public static final String EVENT_NAME_PREFIX = "jdk."; public static final String TYPES_PREFIX = "jdk.types."; public static final String SETTINGS_PREFIX = "jdk.settings."; // Initialization of known types private final static Map<Type, Class<?>> knownTypes = new HashMap<>(); static final Type BOOLEAN = register(boolean.class, new Type("boolean", null, 4)); static final Type CHAR = register(char.class, new Type("char", null, 5)); static final Type FLOAT = register(float.class, new Type("float", null, 6)); static final Type DOUBLE = register(double.class, new Type("double", null, 7)); static final Type BYTE = register(byte.class, new Type("byte", null, 8)); static final Type SHORT = register(short.class, new Type("short", null, 9)); static final Type INT = register(int.class, new Type("int", null, 10)); static final Type LONG = register(long.class, new Type("long", null, 11)); static final Type CLASS = register(Class.class, new Type("java.lang.Class", null, 20)); static final Type STRING = register(String.class, new Type("java.lang.String", null, 21)); static final Type THREAD = register(Thread.class, new Type("java.lang.Thread", null, 22)); static final Type STACK_TRACE = register(null, new Type(TYPES_PREFIX + "StackTrace", null, 23)); private final AnnotationConstruct annos = new AnnotationConstruct(); private final String name; private final String superType; private final boolean constantPool; private List<ValueDescriptor> fields = new ArrayList<>(); private Boolean simpleType; // calculated lazy private boolean remove = true; private long id;
Creates a type
Params:
  • javaTypeName – i.e "java.lang.String"
  • superType – i.e "java.lang.Annotation"
  • id – the class id that represents the class in the JVM
/** * Creates a type * * @param javaTypeName i.e "java.lang.String" * @param superType i.e "java.lang.Annotation" * @param id the class id that represents the class in the JVM * */
public Type(String javaTypeName, String superType, long typeId) { this(javaTypeName, superType, typeId, false); } Type(String javaTypeName, String superType, long typeId, boolean contantPool) { this(javaTypeName, superType, typeId, contantPool, null); } Type(String javaTypeName, String superType, long typeId, boolean contantPool, Boolean simpleType) { Objects.requireNonNull(javaTypeName); if (!isValidJavaIdentifier(javaTypeName)) { throw new IllegalArgumentException(javaTypeName + " is not a valid Java identifier"); } this.constantPool = contantPool; this.superType = superType; this.name = javaTypeName; this.id = typeId; this.simpleType = simpleType; } static boolean isDefinedByJVM(long id) { return id < JVM.RESERVED_CLASS_ID_LIMIT; } public static long getTypeId(Class<?> clazz) { Type type = Type.getKnownType(clazz); return type == null ? JVM.getJVM().getTypeId(clazz) : type.getId(); } static Collection<Type> getKnownTypes() { return knownTypes.keySet(); } public static boolean isValidJavaIdentifier(String identifier) { if (identifier.isEmpty()) { return false; } if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { return false; } for (int i = 1; i < identifier.length(); i++) { char c = identifier.charAt(i); if (c != '.') { if (!Character.isJavaIdentifierPart(c)) { return false; } } } return true; } public static boolean isValidJavaFieldType(String name) { for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) { Class<?> clazz = entry.getValue(); if (clazz != null && name.equals(clazz.getName())) { return true; } } return false; } public static Type getKnownType(String typeName) { for (Type type : knownTypes.keySet()) { if (type.getName().equals(typeName)) { return type; } } return null; } static boolean isKnownType(Class<?> type) { if (type.isPrimitive()) { return true; } if (type.equals(Class.class) || type.equals(Thread.class) || type.equals(String.class)) { return true; } return false; } public static Type getKnownType(Class<?> clazz) { for (Map.Entry<Type, Class<?>> entry : knownTypes.entrySet()) { if (clazz != null && clazz.equals(entry.getValue())) { return entry.getKey(); } } return null; } public String getName() { return name; } public String getLogName() { return getName() + "(" + getId() + ")"; } public List<ValueDescriptor> getFields() { if (fields instanceof ArrayList) { ((ArrayList<ValueDescriptor>) fields).trimToSize(); fields = Collections.unmodifiableList(fields); } return fields; } public boolean isSimpleType() { if (simpleType == null) { simpleType = calculateSimpleType(); } return simpleType.booleanValue(); } private boolean calculateSimpleType() { if (fields.size() != 1) { return false; } // annotation, settings and event can never be simple types return superType == null; } public boolean isDefinedByJVM() { return id < JVM.RESERVED_CLASS_ID_LIMIT; } private static Type register(Class<?> clazz, Type type) { knownTypes.put(type, clazz); return type; } public void add(ValueDescriptor valueDescriptor) { Objects.requireNonNull(valueDescriptor); fields.add(valueDescriptor); } void trimFields() { getFields(); } void setAnnotations(List<AnnotationElement> annotations) { annos.setAnnotationElements(annotations); } public String getSuperType() { return superType; } public long getId() { return id; } public boolean isConstantPool() { return constantPool; } public String getLabel() { return annos.getLabel(); } public List<AnnotationElement> getAnnotationElements() { return annos.getUnmodifiableAnnotationElements(); } public <T> T getAnnotation(Class<? extends java.lang.annotation.Annotation> clazz) { return annos.getAnnotation(clazz); } public String getDescription() { return annos.getDescription(); } @Override public int hashCode() { return Long.hashCode(id); } @Override public boolean equals(Object object) { if (object instanceof Type) { Type that = (Type) object; return that.id == this.id; } return false; } @Override public int compareTo(Type that) { return Long.compare(this.id, that.id); } void log(String action, LogTag logTag, LogLevel level) { if (Logger.shouldLog(logTag, level) && !isSimpleType()) { Logger.log(logTag, LogLevel.TRACE, action + " " + typeText() + " " + getLogName() + " {"); for (ValueDescriptor v : getFields()) { String array = v.isArray() ? "[]" : ""; Logger.log(logTag, LogLevel.TRACE, " " + v.getTypeName() + array + " " + v.getName() + ";"); } Logger.log(logTag, LogLevel.TRACE, "}"); } else { if (Logger.shouldLog(logTag, LogLevel.INFO) && !isSimpleType()) { Logger.log(logTag, LogLevel.INFO, action + " " + typeText() + " " + getLogName()); } } } private String typeText() { if (this instanceof PlatformEventType) { return "event type"; } if (Type.SUPER_TYPE_SETTING.equals(superType)) { return "setting type"; } if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) { return "annotation type"; } return "type"; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getLogName()); if (!getFields().isEmpty()) { sb.append(" {\n"); for (ValueDescriptor td : getFields()) { sb.append(" type=" + td.getTypeName() + "(" + td.getTypeId() + ") name=" + td.getName() + "\n"); } sb.append("}\n"); } return sb.toString(); } public void setRemove(boolean remove) { this.remove = remove; } public boolean getRemove() { return remove; } public void setId(long id) { this.id = id; } }