1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 Ericsson, École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are
5 * made 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 * Patrick Tasse - Initial API and implementation
11 * Matthew Khouzam - Added import functionalities
12 * Geneviève Bastien - Added support for experiment types
13 * Bernd Hufmann - Updated custom trace type ID handling
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.core
.project
.model
;
18 import java
.util
.ArrayList
;
19 import java
.util
.Collections
;
20 import java
.util
.Comparator
;
21 import java
.util
.HashMap
;
22 import java
.util
.LinkedHashMap
;
23 import java
.util
.LinkedList
;
24 import java
.util
.List
;
26 import java
.util
.Map
.Entry
;
28 import org
.eclipse
.core
.resources
.IResource
;
29 import org
.eclipse
.core
.runtime
.CoreException
;
30 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
31 import org
.eclipse
.core
.runtime
.IStatus
;
32 import org
.eclipse
.core
.runtime
.Platform
;
33 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTrace
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTraceDefinition
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
43 * Utility class for accessing TMF trace type extensions from the platform's
44 * extensions registry.
46 * @author Patrick Tasse
47 * @author Matthew Khouzam
49 public final class TmfTraceType
{
51 // ------------------------------------------------------------------
53 // ------------------------------------------------------------------
55 /** Extension point ID */
56 public static final String TMF_TRACE_TYPE_ID
= "org.eclipse.linuxtools.tmf.core.tracetype"; //$NON-NLS-1$
58 /** Extension point element 'Category' */
59 public static final String CATEGORY_ELEM
= "category"; //$NON-NLS-1$
61 /** Extension point element 'Type' */
62 public static final String TYPE_ELEM
= "type"; //$NON-NLS-1$
64 /** Extension point element 'Experiment' */
65 public static final String EXPERIMENT_ELEM
= "experiment"; //$NON-NLS-1$
67 /** Extension point attribute 'ID' */
68 public static final String ID_ATTR
= "id"; //$NON-NLS-1$
70 /** Extension point attribute 'name' */
71 public static final String NAME_ATTR
= "name"; //$NON-NLS-1$
73 /** Extension point attribute 'category' */
74 public static final String CATEGORY_ATTR
= "category"; //$NON-NLS-1$
76 /** Extension point attribute 'trace_type' */
77 public static final String TRACE_TYPE_ATTR
= "trace_type"; //$NON-NLS-1$
79 /** Extension point attribute 'event_type' */
80 public static final String EVENT_TYPE_ATTR
= "event_type"; //$NON-NLS-1$
82 /** Extension point attribute 'experiment_type' */
83 public static final String EXPERIMENT_TYPE_ATTR
= "experiment_type"; //$NON-NLS-1$
85 /** Extension point attribute 'isDirectory' */
86 public static final String IS_DIR_ATTR
= "isDirectory"; //$NON-NLS-1$
88 /** Default experiment type */
89 public static final String DEFAULT_EXPERIMENT_TYPE
= "org.eclipse.linuxtools.tmf.core.experiment.generic"; //$NON-NLS-1$
91 // The mapping of available trace type IDs to their corresponding
92 // configuration element
93 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_ATTRIBUTES
= new HashMap
<>();
94 private static final Map
<String
, IConfigurationElement
> TRACE_CATEGORIES
= new HashMap
<>();
95 private static final Map
<String
, TraceTypeHelper
> TRACE_TYPES
= new LinkedHashMap
<>();
98 populateCategoriesAndTraceTypes();
99 populateCustomTraceTypes();
103 * Enum to say whether a type applies to a trace or experiment
105 * @author Geneviève Bastien
107 public enum TraceElementType
{
108 /** Trace type applies to trace */
110 /** Trace type applies to experiment */
114 // ------------------------------------------------------------------
116 // ------------------------------------------------------------------
118 private TmfTraceType() {
121 // ------------------------------------------------------------------
123 // ------------------------------------------------------------------
126 * Retrieves the category name from the platform extension registry based on
131 * @return the category name or empty string if not found
133 public static String
getCategoryName(String categoryId
) {
134 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
135 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
136 for (IConfigurationElement element
: elements
) {
137 if (element
.getName().equals(CATEGORY_ELEM
) && element
.getAttribute(ID_ATTR
).equals(categoryId
)) {
138 return element
.getAttribute(NAME_ATTR
);
141 return ""; //$NON-NLS-1$
145 * Retrieves all configuration elements from the platform extension registry
146 * for the trace type extension that apply to traces and not experiments.
148 * @return an array of trace type configuration elements
150 public static IConfigurationElement
[] getTypeElements() {
151 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
152 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
153 List
<IConfigurationElement
> typeElements
= new LinkedList
<>();
154 for (IConfigurationElement element
: elements
) {
155 if (element
.getName().equals(TYPE_ELEM
)) {
156 typeElements
.add(element
);
159 return typeElements
.toArray(new IConfigurationElement
[typeElements
.size()]);
163 * Get an iterable view of the existing trace type IDs.
165 * @return The currently registered trace type IDs
167 public static Iterable
<String
> getTraceTypeIDs() {
168 return TRACE_TYPES
.keySet();
172 * Get an iterable view of the existing trace type helpers.
174 * @return The currently registered trace type helpers
176 public static Iterable
<TraceTypeHelper
> getTraceTypeHelpers() {
177 return TRACE_TYPES
.values();
181 * Returns a list of trace type labels "category : name", ...
183 * Returns only trace types, not experiment types
185 * @return a list of trace type labels
187 public static String
[] getAvailableTraceTypes() {
188 return getAvailableTraceTypes(null);
192 * Returns a list of trace type labels "category : name", ... sorted by
195 * Returns only trace types, not experiment types
198 * Comparator class (type String) or null for alphabetical order.
199 * @return a list of trace type labels sorted according to the given
202 public static String
[] getAvailableTraceTypes(Comparator
<String
> comparator
) {
204 // Generate the list of Category:TraceType to populate the ComboBox
205 List
<String
> traceTypes
= new ArrayList
<>();
207 for (TraceTypeHelper tt
: TRACE_TYPES
.values()) {
208 if (!tt
.isExperimentType()) {
209 traceTypes
.add(tt
.getLabel());
213 if (comparator
== null) {
214 Collections
.sort(traceTypes
);
216 Collections
.sort(traceTypes
, comparator
);
220 return traceTypes
.toArray(new String
[traceTypes
.size()]);
224 * Gets all the custom trace types
226 * @return the list of custom trace types
228 public static List
<String
> getCustomTraceTypes() {
230 List
<String
> traceTypes
= new ArrayList
<>();
231 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
232 String traceTypeName
= def
.definitionName
;
233 traceTypes
.add(traceTypeName
);
235 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
236 String traceTypeName
= def
.definitionName
;
237 traceTypes
.add(traceTypeName
);
242 private static void populateCustomTraceTypes() {
243 // add the custom trace types
244 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
245 CustomTxtTrace trace
= new CustomTxtTrace(def
);
246 String traceTypeId
= trace
.getTraceTypeId();
247 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
248 TRACE_TYPES
.put(traceTypeId
, tt
);
249 // Deregister trace as signal handler because it is only used for
251 TmfSignalManager
.deregister(trace
);
253 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
254 CustomXmlTrace trace
= new CustomXmlTrace(def
);
255 String traceTypeId
= trace
.getTraceTypeId();
256 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
257 TRACE_TYPES
.put(traceTypeId
, tt
);
258 // Deregister trace as signal handler because it is only used for
260 TmfSignalManager
.deregister(trace
);
265 * Add or replace a custom trace type
268 * The custom trace class, either {@link CustomTxtTrace} or
269 * {@link CustomXmlTrace}
271 * The custom parser category
272 * @param definitionName
273 * The custom parser definition name to add or replace
275 public static void addCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
276 String traceTypeId
= null;
277 ITmfTrace trace
= null;
279 if (traceClass
.equals(CustomTxtTrace
.class)) {
280 CustomTxtTraceDefinition def
= CustomTxtTraceDefinition
.load(category
, definitionName
);
282 trace
= new CustomTxtTrace(def
);
283 traceTypeId
= trace
.getTraceTypeId();
285 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
286 CustomXmlTraceDefinition def
= CustomXmlTraceDefinition
.load(category
, definitionName
);
288 trace
= new CustomXmlTrace(def
);
289 traceTypeId
= trace
.getTraceTypeId();
293 if (traceTypeId
!= null && trace
!= null) {
294 TraceTypeHelper helper
= TRACE_TYPES
.get(traceTypeId
);
295 if (helper
!= null) {
296 helper
.getTrace().dispose();
298 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, category
, definitionName
, trace
, false, TraceElementType
.TRACE
);
299 TRACE_TYPES
.put(traceTypeId
, tt
);
300 // Deregister trace as signal handler because it is only used for
302 TmfSignalManager
.deregister(trace
);
307 * Remove a custom trace type
310 * The custom trace class, either {@link CustomTxtTrace} or
311 * {@link CustomXmlTrace}
313 * The custom parser category
314 * @param definitionName
315 * The custom parser definition name to add or replace
317 public static void removeCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
318 String traceTypeId
= null;
319 if (traceClass
.equals(CustomTxtTrace
.class)) {
320 traceTypeId
= CustomTxtTrace
.buildTraceTypeId(category
, definitionName
);
321 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
322 traceTypeId
= CustomXmlTrace
.buildTraceTypeId(category
, definitionName
);
324 if (traceTypeId
!= null) {
325 TraceTypeHelper helper
= TRACE_TYPES
.remove(traceTypeId
);
326 if (helper
!= null) {
327 helper
.getTrace().dispose();
333 * Gets a trace type for a given canonical id
336 * the ID of the trace
337 * @return the return type
339 public static TraceTypeHelper
getTraceType(String id
) {
340 return TRACE_TYPES
.get(id
);
343 private static void populateCategoriesAndTraceTypes() {
344 if (TRACE_TYPES
.isEmpty()) {
345 // Populate the Categories and Trace Types
346 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
347 for (IConfigurationElement ce
: config
) {
348 String elementName
= ce
.getName();
349 if (elementName
.equals(TmfTraceType
.TYPE_ELEM
)) {
350 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
351 TRACE_TYPE_ATTRIBUTES
.put(traceTypeId
, ce
);
352 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
353 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
354 TRACE_CATEGORIES
.put(categoryId
, ce
);
355 } else if (elementName
.equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
356 String experimentTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
357 TRACE_TYPE_ATTRIBUTES
.put(experimentTypeId
, ce
);
360 // create the trace types
361 for (Entry
<String
, IConfigurationElement
> entry
: TRACE_TYPE_ATTRIBUTES
.entrySet()) {
362 IConfigurationElement ce
= entry
.getValue();
363 final String category
= getCategory(ce
);
364 final String attribute
= ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
365 ITmfTrace trace
= null;
366 TraceElementType elementType
= TraceElementType
.TRACE
;
368 if (ce
.getName().equals(TmfTraceType
.TYPE_ELEM
)) {
369 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
370 } else if (ce
.getName().equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
371 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.EXPERIMENT_TYPE_ATTR
);
372 elementType
= TraceElementType
.EXPERIMENT
;
377 // Deregister trace as signal handler because it is only
378 // used for validation
379 TmfSignalManager
.deregister(trace
);
381 final String dirString
= ce
.getAttribute(TmfTraceType
.IS_DIR_ATTR
);
382 boolean isDir
= Boolean
.parseBoolean(dirString
);
384 final String typeId
= entry
.getKey();
385 TraceTypeHelper tt
= new TraceTypeHelper(typeId
, category
, attribute
, trace
, isDir
, elementType
);
386 TRACE_TYPES
.put(typeId
, tt
);
387 } catch (CoreException e
) {
388 Activator
.logError("Unexpected error during populating trace types", e
); //$NON-NLS-1$
395 private static String
getCategory(IConfigurationElement ce
) {
396 final String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
397 if (categoryId
!= null) {
398 IConfigurationElement category
= TRACE_CATEGORIES
.get(categoryId
);
399 if (category
!= null && !category
.getName().equals("")) { //$NON-NLS-1$
400 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
403 return ""; //$NON-NLS-1$
407 * Returns the list of trace categories
409 * @return the list of trace categories
411 public static List
<String
> getTraceCategories() {
412 List
<String
> categoryNames
= new ArrayList
<>();
413 for (String key
: TRACE_TYPES
.keySet()) {
414 final String categoryName
= TRACE_TYPES
.get(key
).getCategoryName();
415 if (!categoryNames
.contains(categoryName
)) {
416 categoryNames
.add(categoryName
);
419 return categoryNames
;
423 * Get the trace type helper classes from category name. Return only the
424 * trace types, not the experiment types
426 * @param categoryName
427 * the categoryName to lookup
428 * @return a list of trace type helper classes {@link TraceTypeHelper}
430 public static List
<TraceTypeHelper
> getTraceTypes(String categoryName
) {
431 List
<TraceTypeHelper
> traceNames
= new ArrayList
<>();
432 for (TraceTypeHelper traceTypeHelper
: TRACE_TYPES
.values()) {
433 if (!traceTypeHelper
.isExperimentType()) {
434 final String storedCategoryName
= traceTypeHelper
.getCategoryName();
435 if (storedCategoryName
.equals(categoryName
)) {
436 traceNames
.add(traceTypeHelper
);
444 * Validate a trace type
446 * @param traceTypeName
447 * the trace category (canonical name)
449 * the file name (and path)
450 * @return true if the trace is of a valid type
452 public static boolean validate(String traceTypeName
, String fileName
) {
453 if (traceTypeName
!= null && !traceTypeName
.isEmpty()) {
454 final TraceTypeHelper traceTypeHelper
= TRACE_TYPES
.get(traceTypeName
);
455 if (traceTypeHelper
== null || !traceTypeHelper
.validate(fileName
).isOK()) {
465 * @param traceToValidate
466 * the trace category (canonical name)
467 * @return true if the trace is of a valid type
469 public static boolean validate(TraceValidationHelper traceToValidate
) {
470 return validate(traceToValidate
.getTraceType(), traceToValidate
.getTraceToScan());
474 * Get a configuration element for a given name
478 * @return the configuration element, can be null
480 public static IConfigurationElement
getTraceAttributes(String traceType
) {
481 return TRACE_TYPE_ATTRIBUTES
.get(traceType
);
485 * Find the id of a trace type by its label "category : name"
488 * the trace type label
489 * @return the trace type id
491 public static String
getTraceTypeId(String label
) {
492 for (Entry
<String
, TraceTypeHelper
> entry
: TRACE_TYPES
.entrySet()) {
493 if (entry
.getValue().getLabel().equals(label
)) {
494 return entry
.getKey();
501 * Checks if a trace is a valid directory trace
504 * the file name (and path)
505 * @return <code>true</code> if the trace is a valid directory trace else
508 public static boolean isDirectoryTrace(String path
) {
509 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= getTraceTypeHelpers();
510 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
511 if (traceTypeHelper
.isDirectoryTraceType() &&
512 (traceTypeHelper
.validate(path
).getSeverity() != IStatus
.ERROR
)) {
522 * @return <code>true</code> it is a directory trace type else else
525 public static boolean isDirectoryTraceType(String traceType
) {
526 if (traceType
!= null) {
527 TraceTypeHelper traceTypeHelper
= getTraceType(traceType
);
528 if (traceTypeHelper
!= null) {
529 return traceTypeHelper
.isDirectoryTraceType();
533 throw new IllegalArgumentException("Invalid trace type string: " + traceType
); //$NON-NLS-1$
537 * Get the trace type id for a resource
541 * @return the trace type id or null if it is not set
542 * @throws CoreException
543 * if the trace type id cannot be accessed
545 public static String
getTraceTypeId(IResource resource
) throws CoreException
{
546 String traceTypeId
= resource
.getPersistentProperties().get(TmfCommonConstants
.TRACETYPE
);
547 return buildCompatibilityTraceTypeId(traceTypeId
);
551 * This methods builds a trace type ID from a given ID taking into
552 * consideration any format changes that were done for the IDs of custom
553 * text or XML traces. For example, such format change took place when
554 * moving to Trace Compass. Trace type IDs that are part of the plug-in
555 * extension for trace types won't be changed.
557 * This method is useful for IDs that were persisted in the workspace before
558 * the format changes (e.g. in the persistent properties of a trace
561 * It ensures backwards compatibility of the workspace for custom text and
565 * the legacy trace type ID
566 * @return the trace type ID in Trace Compass format
568 public static String
buildCompatibilityTraceTypeId(String traceTypeId
) {
569 // Fix custom trace type id with old class name or without category name
570 // for backward compatibility
571 if (traceTypeId
!= null) {
572 String newTraceType
= CustomTxtTrace
.buildCompatibilityTraceTypeId(traceTypeId
);
573 if (newTraceType
.equals(traceTypeId
)) {
574 newTraceType
= CustomXmlTrace
.buildCompatibilityTraceTypeId(traceTypeId
);