1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 15 * and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 18 * conditions and the following disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 22 * endorse or promote products derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package org.openjdk.jmc.flightrecorder.internal.parser.v1; 34 35 import java.io.IOException; 36 import java.text.MessageFormat; 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.Iterator; 40 import java.util.List; 41 import java.util.Map; 42 43 import org.openjdk.jmc.common.collection.FastAccessNumberMap; 44 import org.openjdk.jmc.common.unit.ContentType; 45 import org.openjdk.jmc.common.unit.IUnit; 46 import org.openjdk.jmc.common.unit.StructContentType; 47 import org.openjdk.jmc.common.unit.UnitLookup; 48 import org.openjdk.jmc.common.util.LabeledIdentifier; 49 import org.openjdk.jmc.flightrecorder.internal.InvalidJfrFileException; 50 import org.openjdk.jmc.flightrecorder.internal.parser.LoaderContext; 51 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkMetadata.AnnotatedElement; 52 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkMetadata.AnnotationElement; 53 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkMetadata.ClassElement; 54 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkMetadata.FieldElement; 55 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrFrame; 56 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrJavaClass; 57 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrJavaClassLoader; 58 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrJavaModule; 59 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrJavaPackage; 60 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrMethod; 61 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrOldObject; 62 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrOldObjectArray; 63 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrOldObjectField; 64 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrOldObjectGcRoot; 65 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrStackTrace; 66 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrThread; 67 import org.openjdk.jmc.flightrecorder.internal.parser.v1.StructTypes.JfrThreadGroup; 68 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.AbstractStructReader; 69 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.ArrayReader; 70 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.IValueReader; 71 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.PoolReader; 72 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.PrimitiveReader; 73 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.QuantityReader; 74 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.ReflectiveReader; 75 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.StringReader; 76 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.StructReader; 77 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ValueReaders.TicksTimestampReader; 78 import org.openjdk.jmc.flightrecorder.internal.util.JfrInternalConstants; 79 import org.openjdk.jmc.flightrecorder.messages.internal.Messages; 80 import org.openjdk.jmc.flightrecorder.parser.IEventSink; 81 import org.openjdk.jmc.flightrecorder.parser.ValueField; 82 83 class TypeManager { 84 85 private static class NopEventSink implements IEventSink { 86 @Override 87 public void addEvent(Object[] values) { 88 } 89 } 90 91 private static class SkipFieldsEventSink implements IEventSink { 92 private final IEventSink subSink; 93 private final List<Integer> skipFields; 94 private final Object[] reusableStruct; 95 96 SkipFieldsEventSink(IEventSink subSink, List<Integer> skipFields, int fieldCount) { 97 this.subSink = subSink; 98 this.skipFields = skipFields; 99 reusableStruct = new Object[fieldCount - skipFields.size()]; 100 } 101 102 @Override 103 public void addEvent(Object[] fieldValues) { 104 Iterator<Integer> skipIter = skipFields.iterator(); 105 int skipNext = skipIter.next(); 106 int j = 0; 107 for (int i = 0; i < fieldValues.length; i++) { 108 if (i != skipNext) { 109 reusableStruct[j++] = fieldValues[i]; 110 } else if (skipIter.hasNext()) { 111 skipNext = skipIter.next(); 112 } 113 } 114 subSink.addEvent(reusableStruct); 115 } 116 } 117 118 // NOTE: Using constant pool id as identifier. 119 private static final Map<Long, StructContentType<Object[]>> STRUCT_TYPES = new HashMap<>(); 120 121 private class TypeEntry { 122 private static final String STRUCT_TYPE_CLASS = "java.lang.Class"; //$NON-NLS-1$ 123 private static final String STRUCT_TYPE_THREAD = "java.lang.Thread"; //$NON-NLS-1$ 124 private static final String STRUCT_TYPE_STACK_TRACE = "com.oracle.jfr.types.StackTrace"; //$NON-NLS-1$ 125 private static final String STRUCT_TYPE_STACK_TRACE_2 = "jdk.types.StackTrace"; //$NON-NLS-1$ 126 private static final String STRUCT_TYPE_STACK_FRAME = "com.oracle.jfr.types.StackFrame"; //$NON-NLS-1$ 127 private static final String STRUCT_TYPE_STACK_FRAME_2 = "jdk.types.StackFrame"; //$NON-NLS-1$ 128 private static final String STRUCT_TYPE_METHOD = "com.oracle.jfr.types.Method"; //$NON-NLS-1$ 129 private static final String STRUCT_TYPE_METHOD_2 = "jdk.types.Method"; //$NON-NLS-1$ 130 private static final String STRUCT_TYPE_CLASS_LOADER = "com.oracle.jfr.types.ClassLoader"; //$NON-NLS-1$ 131 private static final String STRUCT_TYPE_CLASS_LOADER_2 = "jdk.types.ClassLoader"; //$NON-NLS-1$ 132 private static final String STRUCT_TYPE_MODULE = "com.oracle.jfr.types.Module"; //$NON-NLS-1$ 133 private static final String STRUCT_TYPE_MODULE_2 = "jdk.types.Module"; //$NON-NLS-1$ 134 private static final String STRUCT_TYPE_PACKAGE = "com.oracle.jfr.types.Package"; //$NON-NLS-1$ 135 private static final String STRUCT_TYPE_PACKAGE_2 = "jdk.types.Package"; //$NON-NLS-1$ 136 private static final String STRUCT_TYPE_OLD_OBJECT = "com.oracle.jfr.types.OldObject"; //$NON-NLS-1$ 137 private static final String STRUCT_TYPE_OLD_OBJECT_2 = "jdk.types.OldObject"; //$NON-NLS-1$ 138 private static final String STRUCT_TYPE_OLD_OBJECT_ARRAY = "com.oracle.jfr.types.OldObjectArray"; //$NON-NLS-1$ 139 private static final String STRUCT_TYPE_OLD_OBJECT_ARRAY_2 = "jdk.types.OldObjectArray"; //$NON-NLS-1$ 140 private static final String STRUCT_TYPE_OLD_OBJECT_FIELD = "com.oracle.jfr.types.OldObjectField"; //$NON-NLS-1$ 141 private static final String STRUCT_TYPE_OLD_OBJECT_FIELD_2 = "jdk.types.OldObjectField"; //$NON-NLS-1$ 142 private static final String STRUCT_TYPE_OLD_OBJECT_GC_ROOT = "com.oracle.jfr.types.OldObjectGcRoot"; //$NON-NLS-1$ 143 private static final String STRUCT_TYPE_OLD_OBJECT_GC_ROOT_2 = "jdk.types.OldObjectGcRoot"; //$NON-NLS-1$ 144 private static final String STRUCT_TYPE_THREAD_GROUP = "com.oracle.jfr.types.ThreadGroup"; //$NON-NLS-1$ 145 private static final String STRUCT_TYPE_THREAD_GROUP_2 = "jdk.types.ThreadGroup"; //$NON-NLS-1$ 146 147 final ClassElement element; 148 final FastAccessNumberMap<Object> constants; 149 private IValueReader reader; 150 151 TypeEntry(ClassElement element) { 152 this(element, new FastAccessNumberMap<>()); 153 } 154 155 /** 156 * Temporary constructor for sharing constants. Only used for Strings. 157 */ 158 TypeEntry(ClassElement element, FastAccessNumberMap<Object> constants) { 159 this.element = element; 160 this.constants = constants; 161 } 162 163 public IValueReader getReader() throws InvalidJfrFileException { 164 if (reader == null) { 165 int fieldCount = element.getFieldCount(); 166 if (element.isSimpleType() && fieldCount == 1) { 167 FieldElement singleField = element.fields.get(0); 168 if (singleField.classId == element.classId) { 169 throw new InvalidJfrFileException( 170 element.typeIdentifier + " is a simple type referring to itself"); //$NON-NLS-1$ 171 } else { 172 reader = createFieldReader(element.fields.get(0), null); 173 } 174 } else if (fieldCount == 0 && element.superType == null) { 175 if (StringReader.STRING.equals(element.typeIdentifier)) { 176 reader = new StringReader(constants); 177 } else { 178 reader = new PrimitiveReader(element.typeIdentifier); 179 } 180 } else { 181 AbstractStructReader typeReader = element.typeIdentifier.startsWith("jdk.") //$NON-NLS-1$ 182 ? createStructReaderV2(element.typeIdentifier, element.label, element.description, 183 fieldCount) 184 : createStructReaderV1(element.typeIdentifier, element.label, element.description, 185 fieldCount); 186 // assign before resolving field since it may be recursive 187 reader = typeReader; 188 for (int i = 0; i < fieldCount; i++) { 189 FieldElement fe = element.fields.get(i); 190 IValueReader reader = createFieldReader(fe, null); 191 String labelOrId = (fe.label == null) ? fe.fieldIdentifier : fe.label; 192 typeReader.addField(fe.fieldIdentifier, labelOrId, fe.description, reader); 193 } 194 } 195 } 196 return reader; 197 } 198 199 private AbstractStructReader createStructReaderV2( 200 String identifier, String name, String description, int fieldCount) { 201 switch (identifier) { 202 case STRUCT_TYPE_THREAD_GROUP_2: 203 return new ReflectiveReader(JfrThreadGroup.class, fieldCount, UnitLookup.THREAD_GROUP); 204 case STRUCT_TYPE_CLASS_LOADER_2: 205 return new ReflectiveReader(JfrJavaClassLoader.class, fieldCount, UnitLookup.CLASS_LOADER); 206 case STRUCT_TYPE_OLD_OBJECT_GC_ROOT_2: 207 return new ReflectiveReader(JfrOldObjectGcRoot.class, fieldCount, UnitLookup.OLD_OBJECT_GC_ROOT); 208 case STRUCT_TYPE_OLD_OBJECT_2: 209 return new ReflectiveReader(JfrOldObject.class, fieldCount, UnitLookup.OLD_OBJECT); 210 case STRUCT_TYPE_OLD_OBJECT_ARRAY_2: 211 return new ReflectiveReader(JfrOldObjectArray.class, fieldCount, UnitLookup.OLD_OBJECT_ARRAY); 212 case STRUCT_TYPE_OLD_OBJECT_FIELD_2: 213 return new ReflectiveReader(JfrOldObjectField.class, fieldCount, UnitLookup.OLD_OBJECT_FIELD); 214 case STRUCT_TYPE_METHOD_2: 215 return new ReflectiveReader(JfrMethod.class, fieldCount, UnitLookup.METHOD); 216 case STRUCT_TYPE_STACK_FRAME_2: 217 return new ReflectiveReader(JfrFrame.class, fieldCount, UnitLookup.STACKTRACE_FRAME); 218 case STRUCT_TYPE_STACK_TRACE_2: 219 return new ReflectiveReader(JfrStackTrace.class, fieldCount, UnitLookup.STACKTRACE); 220 case STRUCT_TYPE_MODULE_2: 221 return new ReflectiveReader(JfrJavaModule.class, fieldCount, UnitLookup.MODULE); 222 case STRUCT_TYPE_PACKAGE_2: 223 return new ReflectiveReader(JfrJavaPackage.class, fieldCount, UnitLookup.PACKAGE); 224 default: 225 synchronized (STRUCT_TYPES) { 226 StructContentType<Object[]> structType = STRUCT_TYPES.get(element.classId); 227 if (structType == null) { 228 structType = new StructContentType<>(element.typeIdentifier, element.label, 229 element.description); 230 STRUCT_TYPES.put(element.classId, structType); 231 } 232 return new StructReader(structType, fieldCount); 233 } 234 } 235 } 236 237 private AbstractStructReader createStructReaderV1( 238 String identifier, String name, String description, int fieldCount) { 239 switch (identifier) { 240 case STRUCT_TYPE_THREAD: 241 return new ReflectiveReader(JfrThread.class, fieldCount, UnitLookup.THREAD); 242 case STRUCT_TYPE_THREAD_GROUP: 243 return new ReflectiveReader(JfrThreadGroup.class, fieldCount, UnitLookup.THREAD_GROUP); 244 case STRUCT_TYPE_CLASS: 245 return new ReflectiveReader(JfrJavaClass.class, fieldCount, UnitLookup.CLASS); 246 case STRUCT_TYPE_CLASS_LOADER: 247 return new ReflectiveReader(JfrJavaClassLoader.class, fieldCount, UnitLookup.CLASS_LOADER); 248 case STRUCT_TYPE_OLD_OBJECT_GC_ROOT: 249 return new ReflectiveReader(JfrOldObjectGcRoot.class, fieldCount, UnitLookup.OLD_OBJECT_GC_ROOT); 250 case STRUCT_TYPE_OLD_OBJECT: 251 return new ReflectiveReader(JfrOldObject.class, fieldCount, UnitLookup.OLD_OBJECT); 252 case STRUCT_TYPE_OLD_OBJECT_ARRAY: 253 return new ReflectiveReader(JfrOldObjectArray.class, fieldCount, UnitLookup.OLD_OBJECT_ARRAY); 254 case STRUCT_TYPE_OLD_OBJECT_FIELD: 255 return new ReflectiveReader(JfrOldObjectField.class, fieldCount, UnitLookup.OLD_OBJECT_FIELD); 256 case STRUCT_TYPE_METHOD: 257 return new ReflectiveReader(JfrMethod.class, fieldCount, UnitLookup.METHOD); 258 case STRUCT_TYPE_STACK_FRAME: 259 return new ReflectiveReader(JfrFrame.class, fieldCount, UnitLookup.STACKTRACE_FRAME); 260 case STRUCT_TYPE_STACK_TRACE: 261 return new ReflectiveReader(JfrStackTrace.class, fieldCount, UnitLookup.STACKTRACE); 262 case STRUCT_TYPE_MODULE: 263 return new ReflectiveReader(JfrJavaModule.class, fieldCount, UnitLookup.MODULE); 264 case STRUCT_TYPE_PACKAGE: 265 return new ReflectiveReader(JfrJavaPackage.class, fieldCount, UnitLookup.PACKAGE); 266 default: 267 synchronized (STRUCT_TYPES) { 268 StructContentType<Object[]> structType = STRUCT_TYPES.get(element.classId); 269 if (structType == null) { 270 structType = new StructContentType<>(element.typeIdentifier, element.label, 271 element.description); 272 STRUCT_TYPES.put(element.classId, structType); 273 } 274 return new StructReader(structType, fieldCount); 275 } 276 } 277 } 278 279 void resolveConstants() throws InvalidJfrFileException { 280 IValueReader r = reader; 281 if (r != null) { 282 for (Object c : constants) { 283 r.resolve(c); 284 // FIXME: During resolve, some constants may become equal. Should we ensure canonical constants? 285 } 286 } 287 } 288 289 void readConstant(IDataInput input) throws InvalidJfrFileException, IOException { 290 // FIXME: Constant lookup can perhaps be optimized (across chunks) 291 long constantIndex = input.readLong(); 292 Object value = constants.get(constantIndex); 293 if (value == null) { 294 value = getReader().read(input, true); 295 constants.put(constantIndex, value); 296 } else { 297 getReader().skip(input); 298 } 299 } 300 } 301 302 private class EventTypeEntry { 303 private final ClassElement element; 304 private final List<IValueReader> valueReaders; 305 private Object[] reusableStruct; 306 private IEventSink eventSink; 307 private LabeledIdentifier eventType; 308 309 EventTypeEntry(ClassElement element) { 310 this.element = element; 311 valueReaders = new ArrayList<>(element.getFieldCount()); 312 } 313 314 void readEvent(IDataInput input) throws InvalidJfrFileException, IOException { 315 for (int i = 0; i < valueReaders.size(); i++) { 316 reusableStruct[i] = valueReaders.get(i).read(input, false); 317 } 318 eventSink.addEvent(reusableStruct); 319 } 320 321 LabeledIdentifier getValueType() { 322 if (eventType == null) { 323 eventType = new LabeledIdentifier(element.typeIdentifier, element.classId, element.label, 324 element.description); 325 } 326 return eventType; 327 } 328 329 void init(LoaderContext context) throws InvalidJfrFileException, IOException { 330 if (context.hideExperimentals() && element.experimental) { 331 eventSink = new NopEventSink(); 332 } else { 333 List<ValueField> fieldsList = new ArrayList<>(); 334 List<Integer> skipFields = new ArrayList<>(); 335 for (int i = 0; i < element.getFieldCount(); i++) { 336 FieldElement fe = element.fields.get(i); 337 String valueType = context.getValueInterpretation(element.typeIdentifier, fe.fieldIdentifier); 338 IValueReader reader = createFieldReader(fe, valueType); 339 String fieldLabel = buildLabel(fe.fieldIdentifier, fe); 340 if (context.hideExperimentals() && fe.experimental) { 341 valueReaders.add(reader); 342 skipFields.add(i); 343 } else if (reader instanceof StructReader) { 344 // Flattening of nested structs 345 ClassElement fieldType = getTypeEntry(fe.classId).element; 346 for (int j = 0; j < fieldType.getFieldCount(); j++) { 347 FieldElement nestedField = fieldType.fields.get(j); 348 String nestedId = fe.fieldIdentifier + ":" + nestedField.fieldIdentifier; //$NON-NLS-1$ 349 String nestedValueType = context.getValueInterpretation(element.typeIdentifier, nestedId); 350 IValueReader nestedReader = createFieldReader(nestedField, nestedValueType); 351 valueReaders.add(nestedReader); 352 String nestedLabel = fieldLabel + " : " //$NON-NLS-1$ 353 + (nestedField.label == null ? nestedField.fieldIdentifier : nestedField.label); 354 fieldsList.add(new ValueField(nestedId, nestedLabel, nestedField.description, 355 nestedReader.getContentType())); 356 } 357 } else { 358 valueReaders.add(reader); 359 fieldsList.add(new ValueField(fe.fieldIdentifier, fieldLabel, fe.description, 360 reader.getContentType())); 361 } 362 } 363 String typeLabel = buildLabel(element.typeIdentifier, element); 364 // FIXME: Consider making the category array into something else, like an event type metadata array? 365 eventSink = context.getSinkFactory().create(element.typeIdentifier, typeLabel, element.category, 366 element.description, fieldsList); 367 reusableStruct = new Object[valueReaders.size()]; 368 if (skipFields.size() > 0) { 369 eventSink = new SkipFieldsEventSink(eventSink, skipFields, reusableStruct.length); 370 } 371 } 372 } 373 } 374 375 private final FastAccessNumberMap<TypeEntry> otherTypes = new FastAccessNumberMap<>(); 376 private final FastAccessNumberMap<EventTypeEntry> eventTypes = new FastAccessNumberMap<>(); 377 private final ChunkStructure header; 378 379 TypeManager(List<ClassElement> classList, LoaderContext context, ChunkStructure header) 380 throws InvalidJfrFileException, IOException { 381 this.header = header; 382 for (ClassElement ce : classList) { 383 if (ce.isEventType()) { 384 eventTypes.put(ce.classId, new EventTypeEntry(ce)); 385 } else { 386 otherTypes.put(ce.classId, new TypeEntry(ce)); 387 } 388 } 389 for (ClassElement ce : classList) { 390 resolveAnnotations(ce); 391 for (int i = 0; i < ce.getFieldCount(); i++) { 392 resolveAnnotations(ce.fields.get(i)); 393 } 394 } 395 396 for (EventTypeEntry ce : eventTypes) { 397 ce.init(context); 398 } 399 } 400 401 void readEvent(long typeId, IDataInput input) throws InvalidJfrFileException, IOException { 402 EventTypeEntry entry = eventTypes.get(typeId); 403 if (entry == null) { 404 throw new InvalidJfrFileException("Event type with id " + typeId + " was not declared"); //$NON-NLS-1$ //$NON-NLS-2$ 405 } 406 entry.readEvent(input); 407 } 408 409 void readConstants(long typeId, IDataInput input, int constantCount) throws InvalidJfrFileException, IOException { 410 TypeEntry entry = getTypeEntry(typeId); 411 for (int j = 0; j < constantCount; j++) { 412 entry.readConstant(input); 413 } 414 } 415 416 void resolveConstants() throws InvalidJfrFileException { 417 for (TypeEntry classEntry : otherTypes) { 418 classEntry.resolveConstants(); 419 } 420 } 421 422 private TypeEntry getTypeEntry(long typeId) throws InvalidJfrFileException { 423 TypeEntry entry = otherTypes.get(typeId); 424 if (entry == null) { 425 throw new InvalidJfrFileException("Class with id " + typeId + " was not declared"); //$NON-NLS-1$ //$NON-NLS-2$ 426 } 427 return entry; 428 } 429 430 private void resolveAnnotations(AnnotatedElement ae) throws InvalidJfrFileException { 431 if (ae.annotations != null) { 432 for (AnnotationElement a : ae.annotations) { 433 ClassElement annotationType = getTypeEntry(a.classId).element; 434 ae.resolveAnnotation(annotationType.typeIdentifier, a.values); 435 } 436 } 437 } 438 439 private IValueReader createFieldReader(FieldElement f, String valueType) throws InvalidJfrFileException { 440 TypeEntry fieldType = getTypeEntry(f.classId); 441 String typeIdentifier = fieldType.element.typeIdentifier; 442 boolean isNumeric = PrimitiveReader.isNumeric(typeIdentifier); 443 IValueReader reader = fieldType.getReader(); 444 if (f.ticksUnitKind == UnitLookup.TIMESPAN) { 445 reader = new QuantityReader(typeIdentifier, header.getTicksTimespanUnit(), f.unsigned); 446 } else if (f.ticksUnitKind == UnitLookup.TIMESTAMP) { 447 reader = new TicksTimestampReader(typeIdentifier, header, f.unsigned); 448 } else if (f.unit != null) { 449 reader = new QuantityReader(typeIdentifier, f.unit, f.unsigned); 450 } else if (isNumeric) { 451 if (JfrInternalConstants.TYPE_IDENTIFIER_VALUE_INTERPRETATION.equals(valueType)) { 452 reader = new TypeIdentifierReader(typeIdentifier, f.unsigned); 453 } else { 454 IUnit unit = UnitLookup.getUnitOrNull(valueType); 455 /* 456 * FIXME: Currently we convert all numbers to quantities. This might not be ideal, 457 * for example for thread IDs. See multiple notes referring to this method in 458 * StructTypes. 459 */ 460 reader = new QuantityReader(typeIdentifier, unit == null ? UnitLookup.NUMBER_UNITY : unit, f.unsigned); 461 } 462 } 463 if (f.isStoredInPool()) { 464 if (isNumeric) { 465 throw new InvalidJfrFileException("Numerics should not be put in constant pools"); //$NON-NLS-1$ 466 } 467 reader = new PoolReader(fieldType.constants, reader.getContentType()); 468 } 469 return f.isArray() ? new ArrayReader(reader) : reader; 470 } 471 472 private static String buildLabel(String id, AnnotatedElement element) { 473 String labelOrId = element.label == null ? id : element.label; 474 return element.experimental 475 ? MessageFormat.format(Messages.getString(Messages.TypeManager_EXPERIMENTAL_TYPE), labelOrId) 476 : labelOrId; 477 } 478 479 private class TypeIdentifierReader implements IValueReader { 480 private final String typeIdentifier; 481 private final boolean unsigned; 482 483 TypeIdentifierReader(String typeIdentifier, boolean unsigned) throws InvalidJfrFileException { 484 this.typeIdentifier = typeIdentifier; 485 this.unsigned = unsigned; 486 } 487 488 @Override 489 public Object read(IDataInput in, boolean allowUnresolvedReference) 490 throws IOException, InvalidJfrFileException { 491 long typeId = PrimitiveReader.readLong(in, typeIdentifier, unsigned); 492 return eventTypes.get(typeId).getValueType(); 493 } 494 495 @Override 496 public Object resolve(Object value) throws InvalidJfrFileException { 497 return value; 498 } 499 500 @Override 501 public void skip(IDataInput in) throws IOException, InvalidJfrFileException { 502 PrimitiveReader.readLong(in, typeIdentifier, unsigned); 503 } 504 505 @Override 506 public ContentType<?> getContentType() { 507 return UnitLookup.LABELED_IDENTIFIER; 508 } 509 } 510 }