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
;
27 import org
.eclipse
.core
.resources
.IResource
;
28 import org
.eclipse
.core
.runtime
.CoreException
;
29 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
30 import org
.eclipse
.core
.runtime
.Platform
;
31 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
32 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
33 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTrace
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTraceDefinition
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
41 * Utility class for accessing TMF trace type extensions from the platform's
42 * extensions registry.
44 * @author Patrick Tasse
45 * @author Matthew Khouzam
47 public final class TmfTraceType
{
49 // ------------------------------------------------------------------
51 // ------------------------------------------------------------------
53 /** Extension point ID */
54 public static final String TMF_TRACE_TYPE_ID
= "org.eclipse.linuxtools.tmf.core.tracetype"; //$NON-NLS-1$
56 /** Extension point element 'Category' */
57 public static final String CATEGORY_ELEM
= "category"; //$NON-NLS-1$
59 /** Extension point element 'Type' */
60 public static final String TYPE_ELEM
= "type"; //$NON-NLS-1$
62 /** Extension point element 'Experiment' */
63 public static final String EXPERIMENT_ELEM
= "experiment"; //$NON-NLS-1$
65 /** Extension point attribute 'ID' */
66 public static final String ID_ATTR
= "id"; //$NON-NLS-1$
68 /** Extension point attribute 'name' */
69 public static final String NAME_ATTR
= "name"; //$NON-NLS-1$
71 /** Extension point attribute 'category' */
72 public static final String CATEGORY_ATTR
= "category"; //$NON-NLS-1$
74 /** Extension point attribute 'trace_type' */
75 public static final String TRACE_TYPE_ATTR
= "trace_type"; //$NON-NLS-1$
77 /** Extension point attribute 'event_type' */
78 public static final String EVENT_TYPE_ATTR
= "event_type"; //$NON-NLS-1$
80 /** Extension point attribute 'experiment_type' */
81 public static final String EXPERIMENT_TYPE_ATTR
= "experiment_type"; //$NON-NLS-1$
83 /** Extension point attribute 'isDirectory' */
84 public static final String IS_DIR_ATTR
= "isDirectory"; //$NON-NLS-1$
86 /** Default experiment type */
87 public static final String DEFAULT_EXPERIMENT_TYPE
= "org.eclipse.linuxtools.tmf.core.experiment.generic"; //$NON-NLS-1$
89 // The mapping of available trace type IDs to their corresponding
90 // configuration element
91 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_ATTRIBUTES
= new HashMap
<>();
92 private static final Map
<String
, IConfigurationElement
> TRACE_CATEGORIES
= new HashMap
<>();
93 private static final Map
<String
, TraceTypeHelper
> TRACE_TYPES
= new LinkedHashMap
<>();
96 populateCategoriesAndTraceTypes();
97 populateCustomTraceTypes();
101 * Enum to say whether a type applies to a trace or experiment
103 * @author Geneviève Bastien
105 public enum TraceElementType
{
106 /** Trace type applies to trace */
108 /** Trace type applies to experiment */
112 // ------------------------------------------------------------------
114 // ------------------------------------------------------------------
116 private TmfTraceType() {
119 // ------------------------------------------------------------------
121 // ------------------------------------------------------------------
124 * Retrieves the category name from the platform extension registry based on
129 * @return the category name or empty string if not found
131 public static String
getCategoryName(String categoryId
) {
132 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
133 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
134 for (IConfigurationElement element
: elements
) {
135 if (element
.getName().equals(CATEGORY_ELEM
) && element
.getAttribute(ID_ATTR
).equals(categoryId
)) {
136 return element
.getAttribute(NAME_ATTR
);
139 return ""; //$NON-NLS-1$
143 * Retrieves all configuration elements from the platform extension registry
144 * for the trace type extension that apply to traces and not experiments.
146 * @return an array of trace type configuration elements
148 public static IConfigurationElement
[] getTypeElements() {
149 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
150 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
151 List
<IConfigurationElement
> typeElements
= new LinkedList
<>();
152 for (IConfigurationElement element
: elements
) {
153 if (element
.getName().equals(TYPE_ELEM
)) {
154 typeElements
.add(element
);
157 return typeElements
.toArray(new IConfigurationElement
[typeElements
.size()]);
161 * Get an iterable view of the existing trace type IDs.
163 * @return The currently registered trace type IDs
165 public static Iterable
<String
> getTraceTypeIDs() {
166 return TRACE_TYPES
.keySet();
170 * Get an iterable view of the existing trace type helpers.
172 * @return The currently registered trace type helpers
174 public static Iterable
<TraceTypeHelper
> getTraceTypeHelpers() {
175 return TRACE_TYPES
.values();
179 * Returns a list of trace type labels "category : name", ...
181 * Returns only trace types, not experiment types
183 * @return a list of trace type labels
185 public static String
[] getAvailableTraceTypes() {
186 return getAvailableTraceTypes(null);
190 * Returns a list of trace type labels "category : name", ... sorted by given comparator.
192 * Returns only trace types, not experiment types
195 * Comparator class (type String) or null for alphabetical order.
196 * @return a list of trace type labels sorted according to the given comparator
198 public static String
[] getAvailableTraceTypes(Comparator
<String
> comparator
) {
200 // Generate the list of Category:TraceType to populate the ComboBox
201 List
<String
> traceTypes
= new ArrayList
<>();
203 for (String key
: TRACE_TYPES
.keySet()) {
204 TraceTypeHelper tt
= TRACE_TYPES
.get(key
);
205 if (!tt
.isExperimentType()) {
206 traceTypes
.add(tt
.getLabel());
210 if (comparator
== null) {
211 Collections
.sort(traceTypes
);
213 Collections
.sort(traceTypes
, comparator
);
217 return traceTypes
.toArray(new String
[traceTypes
.size()]);
221 * Gets all the custom trace types
223 * @return the list of custom trace types
225 public static List
<String
> getCustomTraceTypes() {
227 List
<String
> traceTypes
= new ArrayList
<>();
228 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
229 String traceTypeName
= def
.definitionName
;
230 traceTypes
.add(traceTypeName
);
232 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
233 String traceTypeName
= def
.definitionName
;
234 traceTypes
.add(traceTypeName
);
239 private static void populateCustomTraceTypes() {
240 // add the custom trace types
241 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
242 CustomTxtTrace trace
= new CustomTxtTrace(def
);
243 String traceTypeId
= trace
.getTraceTypeId();
244 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
245 TRACE_TYPES
.put(traceTypeId
, tt
);
246 // Deregister trace as signal handler because it is only used for validation
247 TmfSignalManager
.deregister(trace
);
249 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
250 CustomXmlTrace trace
= new CustomXmlTrace(def
);
251 String traceTypeId
= trace
.getTraceTypeId();
252 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
253 TRACE_TYPES
.put(traceTypeId
, tt
);
254 // Deregister trace as signal handler because it is only used for validation
255 TmfSignalManager
.deregister(trace
);
260 * Add or replace a custom trace type
263 * The custom trace class, either {@link CustomTxtTrace} or
264 * {@link CustomXmlTrace}
266 * The custom parser category
267 * @param definitionName
268 * The custom parser definition name to add or replace
270 public static void addCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
271 String traceTypeId
= null;
272 ITmfTrace trace
= null;
274 if (traceClass
.equals(CustomTxtTrace
.class)) {
275 CustomTxtTraceDefinition def
= CustomTxtTraceDefinition
.load(category
, definitionName
);
277 trace
= new CustomTxtTrace(def
);
278 traceTypeId
= trace
.getTraceTypeId();
280 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
281 CustomXmlTraceDefinition def
= CustomXmlTraceDefinition
.load(category
, definitionName
);
283 trace
= new CustomXmlTrace(def
);
284 traceTypeId
= trace
.getTraceTypeId();
288 if (traceTypeId
!= null && trace
!= null) {
289 TraceTypeHelper helper
= TRACE_TYPES
.get(traceTypeId
);
290 if (helper
!= null) {
291 helper
.getTrace().dispose();
293 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, category
, definitionName
, trace
, false, TraceElementType
.TRACE
);
294 TRACE_TYPES
.put(traceTypeId
, tt
);
295 // Deregister trace as signal handler because it is only used for validation
296 TmfSignalManager
.deregister(trace
);
301 * Remove a custom trace type
304 * The custom trace class, either {@link CustomTxtTrace} or
305 * {@link CustomXmlTrace}
307 * The custom parser category
308 * @param definitionName
309 * The custom parser definition name to add or replace
311 public static void removeCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
312 String traceTypeId
= null;
313 if (traceClass
.equals(CustomTxtTrace
.class)) {
314 traceTypeId
= CustomTxtTrace
.buildTraceTypeId(category
, definitionName
);
315 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
316 traceTypeId
= CustomXmlTrace
.buildTraceTypeId(category
, definitionName
);
318 if (traceTypeId
!= null) {
319 TraceTypeHelper helper
= TRACE_TYPES
.remove(traceTypeId
);
320 if (helper
!= null) {
321 helper
.getTrace().dispose();
327 * Gets a trace type for a given canonical id
330 * the ID of the trace
331 * @return the return type
333 public static TraceTypeHelper
getTraceType(String id
) {
334 return TRACE_TYPES
.get(id
);
337 private static void populateCategoriesAndTraceTypes() {
338 if (TRACE_TYPES
.isEmpty()) {
339 // Populate the Categories and Trace Types
340 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
341 for (IConfigurationElement ce
: config
) {
342 String elementName
= ce
.getName();
343 if (elementName
.equals(TmfTraceType
.TYPE_ELEM
)) {
344 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
345 TRACE_TYPE_ATTRIBUTES
.put(traceTypeId
, ce
);
346 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
347 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
348 TRACE_CATEGORIES
.put(categoryId
, ce
);
349 } else if (elementName
.equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
350 String experimentTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
351 TRACE_TYPE_ATTRIBUTES
.put(experimentTypeId
, ce
);
354 // create the trace types
355 for (String typeId
: TRACE_TYPE_ATTRIBUTES
.keySet()) {
356 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(typeId
);
357 final String category
= getCategory(ce
);
358 final String attribute
= ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
359 ITmfTrace trace
= null;
360 TraceElementType elementType
= TraceElementType
.TRACE
;
362 if (ce
.getName().equals(TmfTraceType
.TYPE_ELEM
)) {
363 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
364 } else if (ce
.getName().equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
365 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.EXPERIMENT_TYPE_ATTR
);
366 elementType
= TraceElementType
.EXPERIMENT
;
371 // Deregister trace as signal handler because it is only
372 // used for validation
373 TmfSignalManager
.deregister(trace
);
375 final String dirString
= ce
.getAttribute(TmfTraceType
.IS_DIR_ATTR
);
376 boolean isDir
= Boolean
.parseBoolean(dirString
);
378 TraceTypeHelper tt
= new TraceTypeHelper(typeId
, category
, attribute
, trace
, isDir
, elementType
);
379 TRACE_TYPES
.put(typeId
, tt
);
380 } catch (CoreException e
) {
381 Activator
.logError("Unexpected error during populating trace types", e
); //$NON-NLS-1$
388 private static String
getCategory(IConfigurationElement ce
) {
389 final String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
390 if (categoryId
!= null) {
391 IConfigurationElement category
= TRACE_CATEGORIES
.get(categoryId
);
392 if (category
!= null && !category
.getName().equals("")) { //$NON-NLS-1$
393 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
396 return ""; //$NON-NLS-1$
400 * Returns the list of trace categories
402 * @return the list of trace categories
404 public static List
<String
> getTraceCategories() {
405 List
<String
> categoryNames
= new ArrayList
<>();
406 for (String key
: TRACE_TYPES
.keySet()) {
407 final String categoryName
= TRACE_TYPES
.get(key
).getCategoryName();
408 if (!categoryNames
.contains(categoryName
)) {
409 categoryNames
.add(categoryName
);
412 return categoryNames
;
416 * Get the trace type helper classes from category name. Return only the
417 * trace types, not the experiment types
419 * @param categoryName
420 * the categoryName to lookup
421 * @return a list of trace type helper classes {@link TraceTypeHelper}
423 public static List
<TraceTypeHelper
> getTraceTypes(String categoryName
) {
424 List
<TraceTypeHelper
> traceNames
= new ArrayList
<>();
425 for (String key
: TRACE_TYPES
.keySet()) {
426 if (!TRACE_TYPES
.get(key
).isExperimentType()) {
427 final String storedCategoryName
= TRACE_TYPES
.get(key
).getCategoryName();
428 if (storedCategoryName
.equals(categoryName
)) {
429 traceNames
.add(TRACE_TYPES
.get(key
));
437 * Validate a trace type
439 * @param traceTypeName
440 * the trace category (canonical name)
442 * the file name (and path)
443 * @return true if the trace is of a valid type
445 public static boolean validate(String traceTypeName
, String fileName
) {
446 if (traceTypeName
!= null && !traceTypeName
.isEmpty()) {
447 final TraceTypeHelper traceTypeHelper
= TRACE_TYPES
.get(traceTypeName
);
448 if (traceTypeHelper
== null || !traceTypeHelper
.validate(fileName
).isOK()) {
458 * @param traceToValidate
459 * the trace category (canonical name)
460 * @return true if the trace is of a valid type
462 public static boolean validate(TraceValidationHelper traceToValidate
) {
463 return validate(traceToValidate
.getTraceType(), traceToValidate
.getTraceToScan());
467 * Get a configuration element for a given name
471 * @return the configuration element, can be null
473 public static IConfigurationElement
getTraceAttributes(String traceType
) {
474 return TRACE_TYPE_ATTRIBUTES
.get(traceType
);
478 * Find the id of a trace type by its label "category : name"
481 * the trace type label
482 * @return the trace type id
484 public static String
getTraceTypeId(String label
) {
485 for (String key
: TRACE_TYPES
.keySet()) {
486 if (TRACE_TYPES
.get(key
).getLabel().equals(label
)) {
494 * Checks if a trace is a valid directory trace
496 * the file name (and path)
497 * @return <code>true</code> if the trace is a valid directory trace else <code>false</code>
499 public static boolean isDirectoryTrace(String path
) {
500 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= getTraceTypeHelpers();
501 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
502 if (traceTypeHelper
.isDirectoryTraceType() &&
503 traceTypeHelper
.validate(path
).isOK()) {
513 * @return <code>true</code> it is a directory trace type else else <code>false</code>
515 public static boolean isDirectoryTraceType(String traceType
) {
516 if (traceType
!= null) {
517 TraceTypeHelper traceTypeHelper
= getTraceType(traceType
);
518 if (traceTypeHelper
!= null) {
519 return traceTypeHelper
.isDirectoryTraceType();
523 throw new IllegalArgumentException("Invalid trace type string: " + traceType
); //$NON-NLS-1$
527 * Get the trace type id for a resource
531 * @return the trace type id or null if it is not set
532 * @throws CoreException
533 * if the trace type id cannot be accessed
535 public static String
getTraceTypeId(IResource resource
) throws CoreException
{
536 String traceTypeId
= resource
.getPersistentProperties().get(TmfCommonConstants
.TRACETYPE
);
537 return buildCompatibilityTraceTypeId(traceTypeId
);
541 * This methods builds a trace type ID from a given ID taking into
542 * consideration any format changes that were done for the IDs of custom
543 * text or XML traces. For example, such format change took place when
544 * moving to Trace Compass. Trace type IDs that are part of the plug-in
545 * extension for trace types won't be changed.
547 * This method is useful for IDs that were persisted in the workspace before
548 * the format changes (e.g. in the persistent properties of a trace
551 * It ensures backwards compatibility of the workspace for custom text and
555 * the legacy trace type ID
556 * @return the trace type ID in Trace Compass format
558 public static String
buildCompatibilityTraceTypeId(String traceTypeId
) {
559 // Fix custom trace type id with old class name or without category name for backward compatibility
560 if (traceTypeId
!= null) {
561 String newTraceType
= CustomTxtTrace
.buildCompatibilityTraceTypeId(traceTypeId
);
562 if (newTraceType
.equals(traceTypeId
)) {
563 newTraceType
= CustomXmlTrace
.buildCompatibilityTraceTypeId(traceTypeId
);