diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java index add9c2f9a4..91429d8f9b 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java @@ -35,7 +35,9 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -73,6 +75,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; /** @@ -247,30 +252,42 @@ private static ICTFMetadataNode parseJsonToTree(String json) throws CTFException Gson gson = builder.create(); String[] jsonBlocks = json.split("\u001e"); //$NON-NLS-1$ + Map metadata = new HashMap<>(); + + // Second pass: expand string references and parse for (int i = 1; i < jsonBlocks.length; i++) { + JsonElement element = JsonParser.parseString(jsonBlocks[i]); + if (element.isJsonObject()) { + JsonObject obj = element.getAsJsonObject(); + expandAliases(obj, metadata); + if (obj.has(JsonMetadataStrings.TYPE) && obj.get(JsonMetadataStrings.TYPE).getAsString().equals(JsonMetadataStrings.FRAGMENT_FIELD_ALIAS)) { + metadata.put(obj.get(JsonMetadataStrings.NAME).getAsString(), obj.get(JsonMetadataStrings.FIELD_CLASS).getAsJsonObject()); + } + } + ICTFMetadataNode fragment; try { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], CTFJsonMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, CTFJsonMetadataNode.class)); } catch (JsonSyntaxException e) { throw new CTFException("Trace cannot be parsed as CTF2"); //$NON-NLS-1$ } String type = fragment.getType(); if (type.equals(JsonMetadataStrings.FRAGMENT_PREAMBLE)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonPreambleMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonPreambleMetadataNode.class)); } else if (type.equals(JsonMetadataStrings.FRAGMENT_TRACE)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonTraceMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonTraceMetadataNode.class)); } else if (type.equals(JsonMetadataStrings.FRAGMENT_CLOCK)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonClockMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonClockMetadataNode.class)); } else if (type.equals(JsonMetadataStrings.FRAGMENT_EVENT_RECORD)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonEventRecordMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonEventRecordMetadataNode.class)); } else if (type.equals(JsonMetadataStrings.FRAGMENT_DATA_STREAM)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonDataStreamMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonDataStreamMetadataNode.class)); if (!jsonBlocks[i].contains("id:")) { //$NON-NLS-1$ ((JsonDataStreamMetadataNode) fragment).setId(-1); } } else if (type.equals(JsonMetadataStrings.FRAGMENT_FIELD_ALIAS)) { - fragment = Objects.requireNonNull(gson.fromJson(jsonBlocks[i], JsonFieldClassAliasMetadataNode.class)); + fragment = Objects.requireNonNull(gson.fromJson(element, JsonFieldClassAliasMetadataNode.class)); } ((CTFJsonMetadataNode) fragment).initialize(); @@ -281,6 +298,23 @@ private static ICTFMetadataNode parseJsonToTree(String json) throws CTFException return root; } + private static void expandAliases(JsonObject obj, Map metadata) { + for (String key : obj.keySet()) { + JsonElement value = obj.get(key); + if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString() && metadata.containsKey(value.getAsString())) { + obj.add(key, metadata.get(value.getAsString())); + } else if (value.isJsonObject()) { + expandAliases(value.getAsJsonObject(), metadata); + } else if (value.isJsonArray()) { + for (JsonElement elem : value.getAsJsonArray()) { + if (elem.isJsonObject()) { + expandAliases(elem.getAsJsonObject(), metadata); + } + } + } + } + } + /** * Checks the version of the CTF trace by reading the first JSON fragment if * it is a CTF2 fragment it updates the major of the trace diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java index 81dd29fcee..d35010dc8d 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java @@ -22,6 +22,7 @@ import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope; import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; +import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration; import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; import org.eclipse.tracecompass.ctf.parser.CTFParser; @@ -266,7 +267,7 @@ public VariantDeclaration parse(ICTFMetadataNode variant, ICommonTreeParserParam if (variant instanceof JsonStructureFieldMemberMetadataNode) { JsonObject fieldClass = ((JsonStructureFieldMemberMetadataNode) variant).getFieldClass().getAsJsonObject(); if (fieldClass.has(SELECTOR_FIELD_LOCATION)) { - JsonArray location = fieldClass.get(SELECTOR_FIELD_LOCATION).getAsJsonArray(); + JsonArray location = (fieldClass.get(SELECTOR_FIELD_LOCATION).getAsJsonObject().get(JsonMetadataStrings.PATH)).getAsJsonArray(); variantTag = location.get(location.size() - 1).getAsString(); hasTag = true; } @@ -361,13 +362,17 @@ public VariantDeclaration parse(ICTFMetadataNode variant, ICommonTreeParserParam if (decl == null) { throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$ } - if (!(decl instanceof EnumDeclaration)) { - throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$ - } - EnumDeclaration tagDecl = (EnumDeclaration) decl; - if (!intersects(tagDecl.getLabels(), variantDeclaration.getFields().keySet())) { - throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$ + if (decl instanceof EnumDeclaration) { + EnumDeclaration tagDecl = (EnumDeclaration) decl; + if (!intersects(tagDecl.getLabels(), variantDeclaration.getFields().keySet())) { + throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$ + } + } else if (decl instanceof IntegerDeclaration) { + // do nothing + } else { + throw new ParseException("Variant tag must be an enum: " + variantTag);//$NON-NLS-1$ } + } return variantDeclaration; diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java index 6af764f398..a60efc3008 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java @@ -43,6 +43,17 @@ private JsonMetadataStrings() { */ public static final String FRAGMENT_FIELD_ALIAS = "field-class-alias"; //$NON-NLS-1$ + /** + * The field class + */ + public static final String FIELD_CLASS = "field-class"; //$NON-NLS-1$ + + /** + * The name of the fragment + */ + public static final String NAME = "name"; //$NON-NLS-1$ + + /** * Type string for a CTF2 clock class fragment */ @@ -162,6 +173,11 @@ private JsonMetadataStrings() { */ public static final String VARIANT = "variant"; //$NON-NLS-1$ + /** + * Type string for a structure field class + */ + public static final String PATH = "path"; //$NON-NLS-1$ + /** * Type string for a structure field class */