1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Matthew Khouzam - Initial API and implementation
11 * Alexandre Montplaisir - Initial API and implementation, extend TmfEventField
12 * Bernd Hufmann - Add Enum field handling
13 * Geneviève Bastien - Add Struct and Variant field handling
14 * Jean-Christian Kouame - Correct handling of unsigned integer fields
15 * François Doray - Add generic array field type
16 *******************************************************************************/
18 package org
.eclipse
.tracecompass
.tmf
.ctf
.core
.event
;
20 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
22 import java
.util
.ArrayList
;
23 import java
.util
.Arrays
;
24 import java
.util
.List
;
26 import org
.eclipse
.jdt
.annotation
.NonNull
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.AbstractArrayDefinition
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.CompoundDeclaration
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.Definition
;
30 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.EnumDefinition
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.FloatDefinition
;
32 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.ICompositeDefinition
;
33 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
34 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDefinition
;
35 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDeclaration
;
36 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDefinition
;
37 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StringDefinition
;
38 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.VariantDefinition
;
39 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.ByteArrayDefinition
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventField
;
42 import org
.eclipse
.tracecompass
.tmf
.ctf
.core
.CtfEnumPair
;
45 * The CTF implementation of the TMF event field model
48 * @author Matthew Khouzam
49 * @author Alexandre Montplaisir
51 public abstract class CtfTmfEventField
extends TmfEventField
{
54 * Value that can be used in the {@link #getField(String...)} for variants.
55 * Using this field value means that the selected field will be returned
56 * whatever the selected choice for the event
60 public static final @NonNull String FIELD_VARIANT_SELECTED
= "Any"; //$NON-NLS-1$
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
67 * Standard constructor. Only to be used internally, call parseField() to
68 * generate a new field object.
71 * The name of this field
73 * The value of this field. Its type should match the field type.
75 * The children fields. Useful for composite fields
77 protected CtfTmfEventField(@NonNull String name
, Object value
, ITmfEventField
[] fields
) {
78 super(/* Strip the underscore from the field name if there is one */
79 name
.startsWith("_") ? name
.substring(1) : name
, //$NON-NLS-1$
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
89 * Factory method to instantiate CtfTmfEventField objects.
92 * The CTF Definition of this event field
94 * String The name to assign to this field
95 * @return The resulting CtfTmfEventField object
96 * @deprecated use {@link CtfTmfEventField#parseField(IDefinition, String)}
99 public static CtfTmfEventField
parseField(Definition fieldDef
,
100 @NonNull String fieldName
) {
101 return parseField((IDefinition
) fieldDef
, fieldName
);
105 * Factory method to instantiate CtfTmfEventField objects.
108 * The CTF Definition of this event field
110 * String The name to assign to this field
111 * @return The resulting CtfTmfEventField object
113 public static @NonNull CtfTmfEventField
parseField(IDefinition fieldDef
,
114 @NonNull String fieldName
) {
115 CtfTmfEventField field
= null;
117 /* Determine the Definition type */
118 if (fieldDef
instanceof IntegerDefinition
) {
119 IntegerDefinition intDef
= (IntegerDefinition
) fieldDef
;
120 int base
= intDef
.getDeclaration().getBase();
121 field
= new CTFIntegerField(fieldName
, intDef
.getValue(), base
, intDef
.getDeclaration().isSigned());
123 } else if (fieldDef
instanceof EnumDefinition
) {
124 EnumDefinition enumDef
= (EnumDefinition
) fieldDef
;
125 field
= new CTFEnumField(fieldName
, new CtfEnumPair(enumDef
.getValue(), enumDef
.getIntegerValue()));
127 } else if (fieldDef
instanceof StringDefinition
) {
128 field
= new CTFStringField(fieldName
, ((StringDefinition
) fieldDef
).getValue());
130 } else if (fieldDef
instanceof FloatDefinition
) {
131 FloatDefinition floatDef
= (FloatDefinition
) fieldDef
;
132 field
= new CTFFloatField(fieldName
, floatDef
.getValue());
134 } else if (fieldDef
instanceof AbstractArrayDefinition
) {
135 AbstractArrayDefinition arrayDef
= (AbstractArrayDefinition
) fieldDef
;
136 IDeclaration decl
= arrayDef
.getDeclaration();
137 if (!(decl
instanceof CompoundDeclaration
)) {
138 throw new IllegalArgumentException("Array definitions should only come from sequence or array declarations"); //$NON-NLS-1$
140 CompoundDeclaration arrDecl
= (CompoundDeclaration
) decl
;
141 IDeclaration elemType
= null;
142 elemType
= arrDecl
.getElementType();
143 if (elemType
instanceof IntegerDeclaration
) {
145 * Array of integers => CTFIntegerArrayField, unless it's a
148 IntegerDeclaration elemIntType
= (IntegerDeclaration
) elemType
;
149 /* Are the integers characters and encoded? */
150 if (elemIntType
.isCharacter()) {
151 /* it's a CTFStringField */
152 field
= new CTFStringField(fieldName
, arrayDef
.toString());
153 } else if (arrayDef
instanceof ByteArrayDefinition
) { // unsigned byte array
154 ByteArrayDefinition byteArrayDefinition
= (ByteArrayDefinition
) arrayDef
;
155 /* it's a CTFIntegerArrayField */
156 int size
= arrayDef
.getLength();
157 long[] values
= new long[size
];
158 for (int i
= 0; i
< size
; i
++) {
159 values
[i
] = Byte
.toUnsignedLong(byteArrayDefinition
.getByte(i
));
161 field
= new CTFIntegerArrayField(fieldName
, values
,
162 elemIntType
.getBase(),
163 elemIntType
.isSigned());
166 /* it's a CTFIntegerArrayField */
167 int size
= arrayDef
.getLength();
168 long[] values
= new long[size
];
169 for (int i
= 0; i
< size
; i
++) {
170 IDefinition elem
= arrayDef
.getDefinitions().get(i
);
174 values
[i
] = ((IntegerDefinition
) elem
).getValue();
176 field
= new CTFIntegerArrayField(fieldName
, values
,
177 elemIntType
.getBase(),
178 elemIntType
.isSigned());
181 /* Arrays of elements of any other type */
182 CtfTmfEventField
[] elements
= new CtfTmfEventField
[arrayDef
.getLength()];
183 /* Parse the elements of the array. */
185 List
<Definition
> definitions
= arrayDef
.getDefinitions();
186 for (IDefinition definition
: definitions
) {
187 CtfTmfEventField curField
= CtfTmfEventField
.parseField(
188 definition
, fieldName
+ '[' + i
+ ']');
189 elements
[i
] = curField
;
193 field
= new CTFArrayField(fieldName
, elements
);
195 } else if (fieldDef
instanceof ICompositeDefinition
) {
196 ICompositeDefinition strDef
= (ICompositeDefinition
) fieldDef
;
198 List
<ITmfEventField
> list
= new ArrayList
<>();
199 /* Recursively parse the fields */
200 for (String fn
: strDef
.getFieldNames()) {
201 list
.add(CtfTmfEventField
.parseField((IDefinition
) strDef
.getDefinition(fn
), fn
));
203 field
= new CTFStructField(fieldName
, list
.toArray(new CtfTmfEventField
[list
.size()]));
205 } else if (fieldDef
instanceof VariantDefinition
) {
206 VariantDefinition varDef
= (VariantDefinition
) fieldDef
;
208 String curFieldName
= checkNotNull(varDef
.getCurrentFieldName());
209 IDefinition curFieldDef
= varDef
.getCurrentField();
210 if (curFieldDef
!= null) {
211 CtfTmfEventField subField
= CtfTmfEventField
.parseField(curFieldDef
, curFieldName
);
212 field
= new CTFVariantField(fieldName
, subField
);
214 /* A safe-guard, but curFieldDef should never be null */
215 field
= new CTFStringField(curFieldName
, ""); //$NON-NLS-1$
220 * Safe-guard, to avoid null exceptions later, field is expected not
223 field
= new CTFStringField(fieldName
, Messages
.CtfTmfEventField_UnsupportedType
+ fieldDef
.getClass().toString());
229 public String
toString() {
230 return getName() + '=' + getFormattedValue();
236 * The CTF field implementation for integer fields.
240 final class CTFIntegerField
extends CtfTmfEventField
{
242 private final int fBase
;
243 private final boolean fSigned
;
246 * A CTF "IntegerDefinition" can be an integer of any byte size, so in the
247 * Java parser this is interpreted as a long.
250 * The name of this field
252 * The integer value of this field
254 * Is the value signed or not
256 CTFIntegerField(@NonNull String name
, long longValue
, int base
, boolean signed
) {
257 super(name
, Long
.valueOf(longValue
), null);
263 public Long
getValue() {
264 return (Long
) super.getValue();
268 public String
getFormattedValue() {
269 return IntegerDefinition
.formatNumber(getValue(), fBase
, fSigned
);
275 * The CTF field implementation for string fields
279 final class CTFStringField
extends CtfTmfEventField
{
282 * Constructor for CTFStringField.
285 * The string value of this field
287 * The name of this field
289 CTFStringField(@NonNull String name
, String strValue
) {
290 super(name
, strValue
, null);
294 public String
getValue() {
295 return (String
) super.getValue();
300 * CTF field implementation for arrays of integers.
304 final class CTFIntegerArrayField
extends CtfTmfEventField
{
306 private final int fBase
;
307 private final boolean fSigned
;
308 private String fFormattedValue
= null;
311 * Constructor for CTFIntegerArrayField.
314 * The name of this field
316 * The array of integers (as longs) that compose this field's
319 * Are the values in the array signed or not
321 CTFIntegerArrayField(@NonNull String name
, long[] longValues
, int base
, boolean signed
) {
322 super(name
, longValues
, null);
328 public long[] getValue() {
329 return (long[]) super.getValue();
333 public synchronized String
getFormattedValue() {
334 if (fFormattedValue
== null) {
335 List
<String
> strings
= new ArrayList
<>();
336 for (long value
: getValue()) {
337 strings
.add(IntegerDefinition
.formatNumber(value
, fBase
, fSigned
));
339 fFormattedValue
= strings
.toString();
341 return fFormattedValue
;
347 * CTF field implementation for arrays of arbitrary types.
351 final class CTFArrayField
extends CtfTmfEventField
{
353 private String fFormattedValue
= null;
356 * Constructor for CTFArrayField.
359 * The name of this field
361 * The array elements of this field
363 CTFArrayField(@NonNull String name
, CtfTmfEventField
[] elements
) {
364 super(name
, elements
, elements
);
368 public CtfTmfEventField
[] getValue() {
369 return (CtfTmfEventField
[]) super.getValue();
373 public synchronized String
getFormattedValue() {
374 if (fFormattedValue
== null) {
375 List
<String
> strings
= new ArrayList
<>();
376 for (CtfTmfEventField element
: getValue()) {
377 strings
.add(element
.getFormattedValue());
379 fFormattedValue
= strings
.toString();
381 return fFormattedValue
;
386 * CTF field implementation for floats.
390 final class CTFFloatField
extends CtfTmfEventField
{
393 * Constructor for CTFFloatField.
396 * The float value (actually a double) of this field
398 * The name of this field
400 protected CTFFloatField(@NonNull String name
, double value
) {
401 super(name
, value
, null);
405 public Double
getValue() {
406 return (Double
) super.getValue();
411 * The CTF field implementation for Enum fields
413 * @author Bernd Hufmann
415 final class CTFEnumField
extends CtfTmfEventField
{
418 * Constructor for CTFEnumField.
421 * The Enum value consisting of a pair of Enum value name and its
424 * The name of this field
426 CTFEnumField(@NonNull String name
, CtfEnumPair enumValue
) {
427 super(name
, new CtfEnumPair(enumValue
.getFirst(),
428 enumValue
.getSecond()), null);
432 public CtfEnumPair
getValue() {
433 return (CtfEnumPair
) super.getValue();
438 * The CTF field implementation for struct fields with sub-fields
442 final class CTFStructField
extends CtfTmfEventField
{
445 * Constructor for CTFStructField.
448 * The children of this field
450 * The name of this field
452 CTFStructField(@NonNull String name
, CtfTmfEventField
[] fields
) {
453 super(name
, fields
, fields
);
457 public CtfTmfEventField
[] getValue() {
458 return (CtfTmfEventField
[]) super.getValue();
462 public String
getFormattedValue() {
463 return Arrays
.toString(getValue());
469 * The CTF field implementation for variant fields its child
473 final class CTFVariantField
extends CtfTmfEventField
{
476 * Constructor for CTFVariantField.
479 * The field selected for this variant
481 * The name of this field
483 CTFVariantField(@NonNull String name
, CtfTmfEventField field
) {
484 super(name
, field
, new CtfTmfEventField
[] { field
});
488 public CtfTmfEventField
getValue() {
489 return (CtfTmfEventField
) super.getValue();
493 public ITmfEventField
getField(final String
... path
) {
495 * We use the == to make sure that this constant was used, otherwise, it
496 * could conflict with a field with the same name
498 if (path
.length
== 1 && path
[0] == FIELD_VARIANT_SELECTED
) {
499 return getFields().stream().findFirst().orElse(null);
501 return super.getField(path
);
506 /* Implement other possible fields types here... */