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 *******************************************************************************/
15 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
.CustomTrace
;
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$
90 * Custom text label used internally and therefore should not be
93 public static final String CUSTOM_TXT_CATEGORY
= "Custom Text"; //$NON-NLS-1$
96 * Custom XML label used internally and therefore should not be externalized
98 public static final String CUSTOM_XML_CATEGORY
= "Custom XML"; //$NON-NLS-1$
100 /** Default experiment type */
101 public static final String DEFAULT_EXPERIMENT_TYPE
= "org.eclipse.linuxtools.tmf.core.experiment.generic"; //$NON-NLS-1$
103 // The mapping of available trace type IDs to their corresponding
104 // configuration element
105 private static final Map
<String
, IConfigurationElement
> TRACE_TYPE_ATTRIBUTES
= new HashMap
<>();
106 private static final Map
<String
, IConfigurationElement
> TRACE_CATEGORIES
= new HashMap
<>();
107 private static final Map
<String
, TraceTypeHelper
> TRACE_TYPES
= new LinkedHashMap
<>();
110 populateCategoriesAndTraceTypes();
111 populateCustomTraceTypes();
115 * Enum to say whether a type applies to a trace or experiment
117 * @author Geneviève Bastien
119 public enum TraceElementType
{
120 /** Trace type applies to trace */
122 /** Trace type applies to experiment */
126 // ------------------------------------------------------------------
128 // ------------------------------------------------------------------
130 private TmfTraceType() {
133 // ------------------------------------------------------------------
135 // ------------------------------------------------------------------
138 * Retrieves the category name from the platform extension registry based on
143 * @return the category name or empty string if not found
145 public static String
getCategoryName(String categoryId
) {
146 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
147 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
148 for (IConfigurationElement element
: elements
) {
149 if (element
.getName().equals(CATEGORY_ELEM
) && element
.getAttribute(ID_ATTR
).equals(categoryId
)) {
150 return element
.getAttribute(NAME_ATTR
);
153 return ""; //$NON-NLS-1$
157 * Retrieves all configuration elements from the platform extension registry
158 * for the trace type extension that apply to traces and not experiments.
160 * @return an array of trace type configuration elements
162 public static IConfigurationElement
[] getTypeElements() {
163 IConfigurationElement
[] elements
= Platform
.getExtensionRegistry()
164 .getConfigurationElementsFor(TMF_TRACE_TYPE_ID
);
165 List
<IConfigurationElement
> typeElements
= new LinkedList
<>();
166 for (IConfigurationElement element
: elements
) {
167 if (element
.getName().equals(TYPE_ELEM
)) {
168 typeElements
.add(element
);
171 return typeElements
.toArray(new IConfigurationElement
[typeElements
.size()]);
175 * Get an iterable view of the existing trace type IDs.
177 * @return The currently registered trace type IDs
179 public static Iterable
<String
> getTraceTypeIDs() {
180 return TRACE_TYPES
.keySet();
184 * Get an iterable view of the existing trace type helpers.
186 * @return The currently registered trace type helpers
188 public static Iterable
<TraceTypeHelper
> getTraceTypeHelpers() {
189 return TRACE_TYPES
.values();
193 * Returns a list of trace type labels "category : name", ...
195 * Returns only trace types, not experiment types
197 * @return a list of trace type labels
199 public static String
[] getAvailableTraceTypes() {
200 return getAvailableTraceTypes(null);
204 * Returns a list of trace type labels "category : name", ... sorted by given comparator.
206 * Returns only trace types, not experiment types
209 * Comparator class (type String) or null for alphabetical order.
210 * @return a list of trace type labels sorted according to the given comparator
212 public static String
[] getAvailableTraceTypes(Comparator
<String
> comparator
) {
214 // Generate the list of Category:TraceType to populate the ComboBox
215 List
<String
> traceTypes
= new ArrayList
<>();
217 for (String key
: TRACE_TYPES
.keySet()) {
218 TraceTypeHelper tt
= TRACE_TYPES
.get(key
);
219 if (!tt
.isExperimentType()) {
220 traceTypes
.add(tt
.getLabel());
224 if (comparator
== null) {
225 Collections
.sort(traceTypes
);
227 Collections
.sort(traceTypes
, comparator
);
231 return traceTypes
.toArray(new String
[traceTypes
.size()]);
235 * Gets the custom trace types (custom text and friends)
238 * the type to get (Text, xml or other...)
239 * @return the list of custom trace types
241 public static List
<String
> getCustomTraceTypes(String type
) {
242 List
<String
> traceTypes
= new ArrayList
<>();
243 if (type
.equals(CUSTOM_TXT_CATEGORY
)) {
244 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
245 String traceTypeName
= def
.definitionName
;
246 traceTypes
.add(traceTypeName
);
249 if (type
.equals(CUSTOM_XML_CATEGORY
)) {
250 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
251 String traceTypeName
= def
.definitionName
;
252 traceTypes
.add(traceTypeName
);
259 * Gets all the custom trace types
261 * @return the list of custom trace types
263 public static List
<String
> getCustomTraceTypes() {
265 List
<String
> traceTypes
= new ArrayList
<>();
266 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
267 String traceTypeName
= def
.definitionName
;
268 traceTypes
.add(traceTypeName
);
270 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
271 String traceTypeName
= def
.definitionName
;
272 traceTypes
.add(traceTypeName
);
277 private static void populateCustomTraceTypes() {
278 // add the custom trace types
279 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
280 CustomTxtTrace trace
= new CustomTxtTrace(def
);
281 String traceTypeId
= trace
.getTraceTypeId();
282 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
283 TRACE_TYPES
.put(traceTypeId
, tt
);
284 // Deregister trace as signal handler because it is only used for validation
285 TmfSignalManager
.deregister(trace
);
287 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
288 CustomXmlTrace trace
= new CustomXmlTrace(def
);
289 String traceTypeId
= trace
.getTraceTypeId();
290 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, def
.categoryName
, def
.definitionName
, trace
, false, TraceElementType
.TRACE
);
291 TRACE_TYPES
.put(traceTypeId
, tt
);
292 // Deregister trace as signal handler because it is only used for validation
293 TmfSignalManager
.deregister(trace
);
298 * Add or replace a custom trace type
301 * The custom parser category
302 * @param definitionName
303 * The custom parser definition name to add or replace
304 * @deprecated Use {@link #addCustomTraceType(Class, String, String)}
307 public static void addCustomTraceType(String category
, String definitionName
) {
308 if (category
.equals(CUSTOM_TXT_CATEGORY
)) {
309 addCustomTraceType(CustomTxtTrace
.class, category
, definitionName
);
310 } else if (category
.equals(CUSTOM_XML_CATEGORY
)) {
311 addCustomTraceType(CustomXmlTrace
.class, category
, definitionName
);
316 * Add or replace a custom trace type
319 * The custom trace class, either {@link CustomTxtTrace} or
320 * {@link CustomXmlTrace}
322 * The custom parser category
323 * @param definitionName
324 * The custom parser definition name to add or replace
326 public static void addCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
327 String traceTypeId
= null;
328 CustomTrace trace
= null;
330 if (traceClass
.equals(CustomTxtTrace
.class)) {
331 CustomTxtTraceDefinition def
= CustomTxtTraceDefinition
.load(category
, definitionName
);
333 trace
= new CustomTxtTrace(def
);
334 traceTypeId
= trace
.getTraceTypeId();
336 } else if (traceClass
.equals(CustomXmlTrace
.class)) {
337 CustomXmlTraceDefinition def
= CustomXmlTraceDefinition
.load(category
, definitionName
);
339 trace
= new CustomXmlTrace(def
);
340 traceTypeId
= trace
.getTraceTypeId();
344 if (traceTypeId
!= null && trace
!= null) {
345 TraceTypeHelper helper
= TRACE_TYPES
.get(traceTypeId
);
346 if (helper
!= null) {
347 helper
.getTrace().dispose();
349 TraceTypeHelper tt
= new TraceTypeHelper(traceTypeId
, category
, definitionName
, trace
, false, TraceElementType
.TRACE
);
350 TRACE_TYPES
.put(traceTypeId
, tt
);
351 // Deregister trace as signal handler because it is only used for validation
352 TmfSignalManager
.deregister(trace
);
357 * Remove a custom trace type
360 * The custom parser category
361 * @param definitionName
362 * The custom parser definition name to add or replace
363 * @deprecated Use {@link #removeCustomTraceType(Class, String, String)}
366 public static void removeCustomTraceType(String category
, String definitionName
) {
367 if (category
.equals(CUSTOM_TXT_CATEGORY
)) {
368 removeCustomTraceType(CustomTxtTrace
.class, category
, definitionName
);
369 } else if (category
.equals(CUSTOM_XML_CATEGORY
)) {
370 removeCustomTraceType(CustomXmlTrace
.class, category
, definitionName
);
375 * Remove a custom trace type
378 * The custom trace class, either {@link CustomTxtTrace} or
379 * {@link CustomXmlTrace}
381 * The custom parser category
382 * @param definitionName
383 * The custom parser definition name to add or replace
385 public static void removeCustomTraceType(Class
<?
extends ITmfTrace
> traceClass
, String category
, String definitionName
) {
386 String traceTypeId
= CustomTrace
.buildTraceTypeId(traceClass
, category
, definitionName
);
387 TraceTypeHelper helper
= TRACE_TYPES
.remove(traceTypeId
);
388 if (helper
!= null) {
389 helper
.getTrace().dispose();
394 * Gets a trace type for a given canonical id
397 * the ID of the trace
398 * @return the return type
400 public static TraceTypeHelper
getTraceType(String id
) {
401 return TRACE_TYPES
.get(id
);
404 private static void populateCategoriesAndTraceTypes() {
405 if (TRACE_TYPES
.isEmpty()) {
406 // Populate the Categories and Trace Types
407 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
408 for (IConfigurationElement ce
: config
) {
409 String elementName
= ce
.getName();
410 if (elementName
.equals(TmfTraceType
.TYPE_ELEM
)) {
411 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
412 TRACE_TYPE_ATTRIBUTES
.put(traceTypeId
, ce
);
413 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
414 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
415 TRACE_CATEGORIES
.put(categoryId
, ce
);
416 } else if (elementName
.equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
417 String experimentTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
418 TRACE_TYPE_ATTRIBUTES
.put(experimentTypeId
, ce
);
421 // create the trace types
422 for (String typeId
: TRACE_TYPE_ATTRIBUTES
.keySet()) {
423 IConfigurationElement ce
= TRACE_TYPE_ATTRIBUTES
.get(typeId
);
424 final String category
= getCategory(ce
);
425 final String attribute
= ce
.getAttribute(TmfTraceType
.NAME_ATTR
);
426 ITmfTrace trace
= null;
427 TraceElementType elementType
= TraceElementType
.TRACE
;
429 if (ce
.getName().equals(TmfTraceType
.TYPE_ELEM
)) {
430 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
431 } else if (ce
.getName().equals(TmfTraceType
.EXPERIMENT_ELEM
)) {
432 trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.EXPERIMENT_TYPE_ATTR
);
433 elementType
= TraceElementType
.EXPERIMENT
;
438 // Deregister trace as signal handler because it is only
439 // used for validation
440 TmfSignalManager
.deregister(trace
);
442 final String dirString
= ce
.getAttribute(TmfTraceType
.IS_DIR_ATTR
);
443 boolean isDir
= Boolean
.parseBoolean(dirString
);
445 TraceTypeHelper tt
= new TraceTypeHelper(typeId
, category
, attribute
, trace
, isDir
, elementType
);
446 TRACE_TYPES
.put(typeId
, tt
);
447 } catch (CoreException e
) {
448 Activator
.logError("Unexpected error during populating trace types", e
); //$NON-NLS-1$
455 private static String
getCategory(IConfigurationElement ce
) {
456 final String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
457 if (categoryId
!= null) {
458 IConfigurationElement category
= TRACE_CATEGORIES
.get(categoryId
);
459 if (category
!= null && !category
.getName().equals("")) { //$NON-NLS-1$
460 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
463 return ""; //$NON-NLS-1$
467 * Returns the list of trace categories
469 * @return the list of trace categories
471 public static List
<String
> getTraceCategories() {
472 List
<String
> categoryNames
= new ArrayList
<>();
473 for (String key
: TRACE_TYPES
.keySet()) {
474 final String categoryName
= TRACE_TYPES
.get(key
).getCategoryName();
475 if (!categoryNames
.contains(categoryName
)) {
476 categoryNames
.add(categoryName
);
479 return categoryNames
;
483 * Get the trace type helper classes from category name. Return only the
484 * trace types, not the experiment types
486 * @param categoryName
487 * the categoryName to lookup
488 * @return a list of trace type helper classes {@link TraceTypeHelper}
490 public static List
<TraceTypeHelper
> getTraceTypes(String categoryName
) {
491 List
<TraceTypeHelper
> traceNames
= new ArrayList
<>();
492 for (String key
: TRACE_TYPES
.keySet()) {
493 if (!TRACE_TYPES
.get(key
).isExperimentType()) {
494 final String storedCategoryName
= TRACE_TYPES
.get(key
).getCategoryName();
495 if (storedCategoryName
.equals(categoryName
)) {
496 traceNames
.add(TRACE_TYPES
.get(key
));
504 * Validate a trace type
506 * @param traceTypeName
507 * the trace category (canonical name)
509 * the file name (and path)
510 * @return true if the trace is of a valid type
512 public static boolean validate(String traceTypeName
, String fileName
) {
513 if (traceTypeName
!= null && !traceTypeName
.isEmpty()) {
514 final TraceTypeHelper traceTypeHelper
= TRACE_TYPES
.get(traceTypeName
);
515 if (traceTypeHelper
== null || !traceTypeHelper
.validate(fileName
).isOK()) {
525 * @param traceToValidate
526 * the trace category (canonical name)
527 * @return true if the trace is of a valid type
529 public static boolean validate(TraceValidationHelper traceToValidate
) {
530 return validate(traceToValidate
.getTraceType(), traceToValidate
.getTraceToScan());
534 * Validate a list of files with a tracetype
536 * @param traceTypeName
537 * the trace category (canonical name)
539 * the list of files to check if they are trace
540 * @return true if all the traces are valid
542 public static boolean validateTraceFiles(String traceTypeName
, List
<File
> traces
) {
543 if (traceTypeName
!= null && !"".equals(traceTypeName
) && //$NON-NLS-1$
544 !traceTypeName
.startsWith(TmfTraceType
.CUSTOM_TXT_CATEGORY
) && !traceTypeName
.startsWith(TmfTraceType
.CUSTOM_XML_CATEGORY
)) {
545 for (File trace
: traces
) {
546 if (!validate(traceTypeName
, trace
.getAbsolutePath())) {
555 * Get a configuration element for a given name
559 * @return the configuration element, can be null
561 public static IConfigurationElement
getTraceAttributes(String traceType
) {
562 return TRACE_TYPE_ATTRIBUTES
.get(traceType
);
566 * Find the id of a trace type by its label "category : name"
569 * the trace type label
570 * @return the trace type id
572 public static String
getTraceTypeId(String label
) {
573 for (String key
: TRACE_TYPES
.keySet()) {
574 if (TRACE_TYPES
.get(key
).getLabel().equals(label
)) {
582 * Checks if a trace is a valid directory trace
584 * the file name (and path)
585 * @return <code>true</code> if the trace is a valid directory trace else <code>false</code>
587 public static boolean isDirectoryTrace(String path
) {
588 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= getTraceTypeHelpers();
589 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
590 if (traceTypeHelper
.isDirectoryTraceType() &&
591 traceTypeHelper
.validate(path
).isOK()) {
601 * @return <code>true</code> it is a directory trace type else else <code>false</code>
603 public static boolean isDirectoryTraceType(String traceType
) {
604 if (traceType
!= null) {
605 TraceTypeHelper traceTypeHelper
= getTraceType(traceType
);
606 if (traceTypeHelper
!= null) {
607 return traceTypeHelper
.isDirectoryTraceType();
611 throw new IllegalArgumentException("Invalid trace type string: " + traceType
); //$NON-NLS-1$
615 * Get the trace type id for a resource
619 * @return the trace type id or null if it is not set
620 * @throws CoreException
621 * if the trace type id cannot be accessed
624 public static String
getTraceTypeId(IResource resource
) throws CoreException
{
625 String traceTypeId
= resource
.getPersistentProperties().get(TmfCommonConstants
.TRACETYPE
);
626 // Fix custom trace type id with old class name or without category name for backward compatibility
627 if (traceTypeId
!= null) {
628 int index
= traceTypeId
.lastIndexOf(':');
630 if (traceTypeId
.contains(CustomTxtTrace
.class.getSimpleName() + ':') && traceTypeId
.indexOf(':') == index
) {
631 traceTypeId
= CustomTxtTrace
.class.getCanonicalName() + ':' +
632 TmfTraceType
.CUSTOM_TXT_CATEGORY
+ traceTypeId
.substring(index
);
633 } else if (traceTypeId
.contains(CustomXmlTrace
.class.getSimpleName() + ':') && traceTypeId
.indexOf(':') == index
) {
634 traceTypeId
= CustomXmlTrace
.class.getCanonicalName() + ':' +
635 TmfTraceType
.CUSTOM_XML_CATEGORY
+ traceTypeId
.substring(index
);