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
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Collections
;
21 import java
.util
.Comparator
;
22 import java
.util
.HashMap
;
23 import java
.util
.LinkedHashMap
;
24 import java
.util
.LinkedList
;
25 import java
.util
.List
;
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
.Platform
;
32 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
33 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTrace
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomTxtTraceDefinition
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
42 * Utility class for accessing TMF trace type extensions from the platform's
43 * extensions registry.
46 * @author Patrick Tasse
47 * @author Matthew Khouzam
50 public final class TmfTraceType
{
52 // ------------------------------------------------------------------
54 // ------------------------------------------------------------------
56 /** Extension point ID */
57 public static final String TMF_TRACE_TYPE_ID
= "org.eclipse.linuxtools.tmf.core.tracetype"; //$NON-NLS-1$
59 /** Extension point element 'Category' */
60 public static final String CATEGORY_ELEM
= "category"; //$NON-NLS-1$
62 /** Extension point element 'Type' */
63 public static final String TYPE_ELEM
= "type"; //$NON-NLS-1$
65 /** Extension point element 'Experiment' */
66 public static final String EXPERIMENT_ELEM
= "experiment"; //$NON-NLS-1$
68 /** Extension point attribute 'ID' */
69 public static final String ID_ATTR
= "id"; //$NON-NLS-1$
71 /** Extension point attribute 'name' */
72 public static final String NAME_ATTR
= "name"; //$NON-NLS-1$
74 /** Extension point attribute 'category' */
75 public static final String CATEGORY_ATTR
= "category"; //$NON-NLS-1$
77 /** Extension point attribute 'trace_type' */
78 public static final String TRACE_TYPE_ATTR
= "trace_type"; //$NON-NLS-1$
80 /** Extension point attribute 'event_type' */
81 public static final String EVENT_TYPE_ATTR
= "event_type"; //$NON-NLS-1$
83 /** Extension point attribute 'experiment_type' */
84 public static final String EXPERIMENT_TYPE_ATTR
= "experiment_type"; //$NON-NLS-1$
86 /** Extension point attribute 'isDirectory' */
87 public static final String IS_DIR_ATTR
= "isDirectory"; //$NON-NLS-1$
89 /** Default experiment type */
90 public static final String DEFAULT_EXPERIMENT_TYPE
= "org.eclipse.linuxtools.tmf.core.experiment.generic"; //$NON-NLS-1$
92 // The mapping of available trace type IDs to their corresponding
93 // configuration element
94 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_ATTRIBUTES
= new HashMap
<>();
95 private static final Map
<String
, IConfigurationElement
> TRACE_CATEGORIES
= new HashMap
<>();
96 private static final Map
<String
, TraceTypeHelper
> TRACE_TYPES
= new LinkedHashMap
<>();
99 populateCategoriesAndTraceTypes();
100 populateCustomTraceTypes();
104 * Enum to say whether a type applies to a trace or experiment
106 * @author Geneviève Bastien
108 public enum TraceElementType
{
109 /** Trace type applies to trace */
111 /** Trace type applies to experiment */
115 // ------------------------------------------------------------------
117 // ------------------------------------------------------------------
119 private TmfTraceType() {
122 // ------------------------------------------------------------------
124 // ------------------------------------------------------------------
127 * Retrieves the category name from the platform extension registry based on
132 * @return the category name or empty string if not found
134 public static String
getCategoryName(String categoryId
) {
135 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
136 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
137 for (IConfigurationElement element
: elements
) {
138 if (element
.getName().equals(CATEGORY_ELEM
) && element
.getAttribute(ID_ATTR
).equals(categoryId
)) {
139 return element
.getAttribute(NAME_ATTR
);
142 return ""; //$NON-NLS-1$
146 * Retrieves all configuration elements from the platform extension registry
147 * for the trace type extension that apply to traces and not experiments.
149 * @return an array of trace type configuration elements
151 public static IConfigurationElement
[] getTypeElements() {
152 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
153 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
154 List
<IConfigurationElement
> typeElements
= new LinkedList
<>();
155 for (IConfigurationElement element
: elements
) {
156 if (element
.getName().equals(TYPE_ELEM
)) {
157 typeElements
.add(element
);
160 return typeElements
.toArray(new IConfigurationElement
[typeElements
.size()]);
164 * Get an iterable view of the existing trace type IDs.
166 * @return The currently registered trace type IDs
168 public static Iterable
<String
> getTraceTypeIDs() {
169 return TRACE_TYPES
.keySet();
173 * Get an iterable view of the existing trace type helpers.
175 * @return The currently registered trace type helpers
177 public static Iterable
<TraceTypeHelper
> getTraceTypeHelpers() {
178 return TRACE_TYPES
.values();
182 * Returns a list of trace type labels "category : name", ...
184 * Returns only trace types, not experiment types
186 * @return a list of trace type labels
188 public static String
[] getAvailableTraceTypes() {
189 return getAvailableTraceTypes(null);
193 * Returns a list of trace type labels "category : name", ... sorted by given comparator.
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 comparator
201 public static String
[] getAvailableTraceTypes(Comparator
<String
> comparator
) {
203 // Generate the list of Category:TraceType to populate the ComboBox
204 List
<String
> traceTypes
= new ArrayList
<>();
206 for (String key
: TRACE_TYPES
.keySet()) {
207 TraceTypeHelper tt
= TRACE_TYPES
.get(key
);
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 the custom trace types (custom text and friends)
227 * the type to get (Text, xml or other...)
228 * @return the list of custom trace types
230 public static List
<String
> getCustomTraceTypes(String type
) {
231 List
<String
> traceTypes
= new ArrayList
<>();
232 if (type
.equals(CustomTxtTraceDefinition
.CUSTOM_TXT_CATEGORY
)) {
233 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
234 String traceTypeName
= def
.definitionName
;
235 traceTypes
.add(traceTypeName
);
238 if (type
.equals(CustomXmlTraceDefinition
.CUSTOM_XML_CATEGORY
)) {
239 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
240 String traceTypeName
= def
.definitionName
;
241 traceTypes
.add(traceTypeName
);
248 * Gets all the custom trace types
250 * @return the list of custom trace types
252 public static List
<String
> getCustomTraceTypes() {
254 List
<String
> traceTypes
= new ArrayList
<>();
255 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
256 String traceTypeName
= def
.definitionName
;
257 traceTypes
.add(traceTypeName
);
259 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
260 String traceTypeName
= def
.definitionName
;
261 traceTypes
.add(traceTypeName
);
266 private static void populateCustomTraceTypes() {
267 // add the custom trace types
268 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
269 CustomTxtTrace trace
= new CustomTxtTrace(def
);
270 String traceTypeId
= trace
.getTraceTypeId();
271 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
272 TRACE_TYPES
.put(traceTypeId
, tt
);
273 // Deregister trace as signal handler because it is only used for validation
274 TmfSignalManager
.deregister(trace
);
276 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
277 CustomXmlTrace trace
= new CustomXmlTrace(def
);
278 String traceTypeId
= trace
.getTraceTypeId();
279 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
280 TRACE_TYPES
.put(traceTypeId
, tt
);
281 // Deregister trace as signal handler because it is only used for validation
282 TmfSignalManager
.deregister(trace
);
287 * Add or replace a custom trace type
290 * The custom parser category
291 * @param definitionName
292 * The custom parser definition name to add or replace
293 * @deprecated Use {@link #addCustomTraceType(Class, String, String)}
296 public static void addCustomTraceType(String category
, String definitionName
) {
297 if (category
.equals(CustomTxtTraceDefinition
.CUSTOM_TXT_CATEGORY
)) {
298 addCustomTraceType(CustomTxtTrace
.class, category
, definitionName
);
299 } else if (category
.equals(CustomXmlTraceDefinition
.CUSTOM_XML_CATEGORY
)) {
300 addCustomTraceType(CustomXmlTrace
.class, category
, definitionName
);
305 * Add or replace a custom trace type
308 * The custom trace class, either {@link CustomTxtTrace} or
309 * {@link CustomXmlTrace}
311 * The custom parser category
312 * @param definitionName
313 * The custom parser definition name to add or replace
315 public static void addCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
316 String traceTypeId
= null;
317 ITmfTrace trace
= null;
319 if (traceClass
.equals(CustomTxtTrace
.class)) {
320 CustomTxtTraceDefinition def
= CustomTxtTraceDefinition
.load(category
, definitionName
);
322 trace
= new CustomTxtTrace(def
);
323 traceTypeId
= trace
.getTraceTypeId();
325 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
326 CustomXmlTraceDefinition def
= CustomXmlTraceDefinition
.load(category
, definitionName
);
328 trace
= new CustomXmlTrace(def
);
329 traceTypeId
= trace
.getTraceTypeId();
333 if (traceTypeId
!= null && trace
!= null) {
334 TraceTypeHelper helper
= TRACE_TYPES
.get(traceTypeId
);
335 if (helper
!= null) {
336 helper
.getTrace().dispose();
338 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, category
, definitionName
, trace
, false, TraceElementType
.TRACE
);
339 TRACE_TYPES
.put(traceTypeId
, tt
);
340 // Deregister trace as signal handler because it is only used for validation
341 TmfSignalManager
.deregister(trace
);
346 * Remove a custom trace type
349 * The custom parser category
350 * @param definitionName
351 * The custom parser definition name to add or replace
352 * @deprecated Use {@link #removeCustomTraceType(Class, String, String)}
355 public static void removeCustomTraceType(String category
, String definitionName
) {
356 if (category
.equals(CustomTxtTraceDefinition
.CUSTOM_TXT_CATEGORY
)) {
357 removeCustomTraceType(CustomTxtTrace
.class, category
, definitionName
);
358 } else if (category
.equals(CustomXmlTraceDefinition
.CUSTOM_XML_CATEGORY
)) {
359 removeCustomTraceType(CustomXmlTrace
.class, category
, definitionName
);
364 * Remove a custom trace type
367 * The custom trace class, either {@link CustomTxtTrace} or
368 * {@link CustomXmlTrace}
370 * The custom parser category
371 * @param definitionName
372 * The custom parser definition name to add or replace
374 public static void removeCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
375 String traceTypeId
= null;
376 if (traceClass
.equals(CustomTxtTrace
.class)) {
377 traceTypeId
= CustomTxtTrace
.buildTraceTypeId(category
, definitionName
);
378 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
379 traceTypeId
= CustomXmlTrace
.buildTraceTypeId(category
, definitionName
);
381 if (traceTypeId
!= null) {
382 TraceTypeHelper helper
= TRACE_TYPES
.remove(traceTypeId
);
383 if (helper
!= null) {
384 helper
.getTrace().dispose();
390 * Gets a trace type for a given canonical id
393 * the ID of the trace
394 * @return the return type
396 public static TraceTypeHelper
getTraceType(String id
) {
397 return TRACE_TYPES
.get(id
);
400 private static void populateCategoriesAndTraceTypes() {
401 if (TRACE_TYPES
.isEmpty()) {
402 // Populate the Categories and Trace Types
403 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
404 for (IConfigurationElement ce
: config
) {
405 String elementName
= ce
.getName();
406 if (elementName
.equals(TmfTraceType
.TYPE_ELEM
)) {
407 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
408 TRACE_TYPE_ATTRIBUTES
.put(traceTypeId
, ce
);
409 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
410 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
411 TRACE_CATEGORIES
.put(categoryId
, ce
);
412 } else if (elementName
.equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
413 String experimentTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
414 TRACE_TYPE_ATTRIBUTES
.put(experimentTypeId
, ce
);
417 // create the trace types
418 for (String typeId
: TRACE_TYPE_ATTRIBUTES
.keySet()) {
419 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(typeId
);
420 final String category
= getCategory(ce
);
421 final String attribute
= ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
422 ITmfTrace trace
= null;
423 TraceElementType elementType
= TraceElementType
.TRACE
;
425 if (ce
.getName().equals(TmfTraceType
.TYPE_ELEM
)) {
426 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
427 } else if (ce
.getName().equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
428 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.EXPERIMENT_TYPE_ATTR
);
429 elementType
= TraceElementType
.EXPERIMENT
;
434 // Deregister trace as signal handler because it is only
435 // used for validation
436 TmfSignalManager
.deregister(trace
);
438 final String dirString
= ce
.getAttribute(TmfTraceType
.IS_DIR_ATTR
);
439 boolean isDir
= Boolean
.parseBoolean(dirString
);
441 TraceTypeHelper tt
= new TraceTypeHelper(typeId
, category
, attribute
, trace
, isDir
, elementType
);
442 TRACE_TYPES
.put(typeId
, tt
);
443 } catch (CoreException e
) {
444 Activator
.logError("Unexpected error during populating trace types", e
); //$NON-NLS-1$
451 private static String
getCategory(IConfigurationElement ce
) {
452 final String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
453 if (categoryId
!= null) {
454 IConfigurationElement category
= TRACE_CATEGORIES
.get(categoryId
);
455 if (category
!= null && !category
.getName().equals("")) { //$NON-NLS-1$
456 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
459 return ""; //$NON-NLS-1$
463 * Returns the list of trace categories
465 * @return the list of trace categories
467 public static List
<String
> getTraceCategories() {
468 List
<String
> categoryNames
= new ArrayList
<>();
469 for (String key
: TRACE_TYPES
.keySet()) {
470 final String categoryName
= TRACE_TYPES
.get(key
).getCategoryName();
471 if (!categoryNames
.contains(categoryName
)) {
472 categoryNames
.add(categoryName
);
475 return categoryNames
;
479 * Get the trace type helper classes from category name. Return only the
480 * trace types, not the experiment types
482 * @param categoryName
483 * the categoryName to lookup
484 * @return a list of trace type helper classes {@link TraceTypeHelper}
486 public static List
<TraceTypeHelper
> getTraceTypes(String categoryName
) {
487 List
<TraceTypeHelper
> traceNames
= new ArrayList
<>();
488 for (String key
: TRACE_TYPES
.keySet()) {
489 if (!TRACE_TYPES
.get(key
).isExperimentType()) {
490 final String storedCategoryName
= TRACE_TYPES
.get(key
).getCategoryName();
491 if (storedCategoryName
.equals(categoryName
)) {
492 traceNames
.add(TRACE_TYPES
.get(key
));
500 * Validate a trace type
502 * @param traceTypeName
503 * the trace category (canonical name)
505 * the file name (and path)
506 * @return true if the trace is of a valid type
508 public static boolean validate(String traceTypeName
, String fileName
) {
509 if (traceTypeName
!= null && !traceTypeName
.isEmpty()) {
510 final TraceTypeHelper traceTypeHelper
= TRACE_TYPES
.get(traceTypeName
);
511 if (traceTypeHelper
== null || !traceTypeHelper
.validate(fileName
).isOK()) {
521 * @param traceToValidate
522 * the trace category (canonical name)
523 * @return true if the trace is of a valid type
525 public static boolean validate(TraceValidationHelper traceToValidate
) {
526 return validate(traceToValidate
.getTraceType(), traceToValidate
.getTraceToScan());
530 * Validate a list of files with a tracetype
532 * @param traceTypeName
533 * the trace category (canonical name)
535 * the list of files to check if they are trace
536 * @return true if all the traces are valid
538 public static boolean validateTraceFiles(String traceTypeName
, List
<File
> traces
) {
539 if (traceTypeName
!= null && !"".equals(traceTypeName
) && //$NON-NLS-1$
540 !traceTypeName
.startsWith(CustomTxtTraceDefinition
.CUSTOM_TXT_CATEGORY
) && !traceTypeName
.startsWith(CustomXmlTraceDefinition
.CUSTOM_XML_CATEGORY
)) {
541 for (File trace
: traces
) {
542 if (!validate(traceTypeName
, trace
.getAbsolutePath())) {
551 * Get a configuration element for a given name
555 * @return the configuration element, can be null
557 public static IConfigurationElement
getTraceAttributes(String traceType
) {
558 return TRACE_TYPE_ATTRIBUTES
.get(traceType
);
562 * Find the id of a trace type by its label "category : name"
565 * the trace type label
566 * @return the trace type id
568 public static String
getTraceTypeId(String label
) {
569 for (String key
: TRACE_TYPES
.keySet()) {
570 if (TRACE_TYPES
.get(key
).getLabel().equals(label
)) {
578 * Checks if a trace is a valid directory trace
580 * the file name (and path)
581 * @return <code>true</code> if the trace is a valid directory trace else <code>false</code>
583 public static boolean isDirectoryTrace(String path
) {
584 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= getTraceTypeHelpers();
585 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
586 if (traceTypeHelper
.isDirectoryTraceType() &&
587 traceTypeHelper
.validate(path
).isOK()) {
597 * @return <code>true</code> it is a directory trace type else else <code>false</code>
599 public static boolean isDirectoryTraceType(String traceType
) {
600 if (traceType
!= null) {
601 TraceTypeHelper traceTypeHelper
= getTraceType(traceType
);
602 if (traceTypeHelper
!= null) {
603 return traceTypeHelper
.isDirectoryTraceType();
607 throw new IllegalArgumentException("Invalid trace type string: " + traceType
); //$NON-NLS-1$
611 * Get the trace type id for a resource
615 * @return the trace type id or null if it is not set
616 * @throws CoreException
617 * if the trace type id cannot be accessed
620 public static String
getTraceTypeId(IResource resource
) throws CoreException
{
621 String traceTypeId
= resource
.getPersistentProperties().get(TmfCommonConstants
.TRACETYPE
);
622 // Fix custom trace type id with old class name or without category name for backward compatibility
623 if (traceTypeId
!= null) {
624 String newTraceType
= CustomTxtTrace
.buildCompatibilityTraceTypeId(traceTypeId
);
625 if (newTraceType
.equals(traceTypeId
)) {
626 newTraceType
= CustomXmlTrace
.buildCompatibilityTraceTypeId(traceTypeId
);