/******************************************************************************* * Copyright (c) 2011, 2014 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Patrick Tasse - Initial API and implementation * Matthew Khouzam - Added import functionalities * Geneviève Bastien - Added support for experiment types *******************************************************************************/ package fr.inria.linuxtools.tmf.core.project.model; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import fr.inria.linuxtools.tmf.core.parsers.custom.CustomTxtTrace; import fr.inria.linuxtools.tmf.core.parsers.custom.CustomTxtTraceDefinition; import fr.inria.linuxtools.tmf.core.parsers.custom.CustomXmlTrace; import fr.inria.linuxtools.tmf.core.parsers.custom.CustomXmlTraceDefinition; import fr.inria.linuxtools.tmf.core.signal.TmfSignalManager; import fr.inria.linuxtools.tmf.core.trace.ITmfTrace; /** * Utility class for accessing TMF trace type extensions from the platform's * extensions registry. * * @version 1.0 * @author Patrick Tasse * @author Matthew Khouzam * @since 3.0 */ public final class TmfTraceType { // ------------------------------------------------------------------ // Constants // ------------------------------------------------------------------ private static final char SEPARATOR = ':'; /** Extension point ID */ public static final String TMF_TRACE_TYPE_ID = "fr.inria.linuxtools.tmf.core.tracetype"; //$NON-NLS-1$ /** Extension point element 'Category' */ public static final String CATEGORY_ELEM = "category"; //$NON-NLS-1$ /** Extension point element 'Type' */ public static final String TYPE_ELEM = "type"; //$NON-NLS-1$ /** Extension point element 'Experiment' */ public static final String EXPERIMENT_ELEM = "experiment"; //$NON-NLS-1$ /** Extension point attribute 'ID' */ public static final String ID_ATTR = "id"; //$NON-NLS-1$ /** Extension point attribute 'name' */ public static final String NAME_ATTR = "name"; //$NON-NLS-1$ /** Extension point attribute 'category' */ public static final String CATEGORY_ATTR = "category"; //$NON-NLS-1$ /** Extension point attribute 'trace_type' */ public static final String TRACE_TYPE_ATTR = "trace_type"; //$NON-NLS-1$ /** Extension point attribute 'event_type' */ public static final String EVENT_TYPE_ATTR = "event_type"; //$NON-NLS-1$ /** Extension point attribute 'experiment_type' */ public static final String EXPERIMENT_TYPE_ATTR = "experiment_type"; //$NON-NLS-1$ /** Extension point attribute 'isDirectory' */ public static final String IS_DIR_ATTR = "isDirectory"; //$NON-NLS-1$ /** * Custom text label used internally and therefore should not be * externalized */ public static final String CUSTOM_TXT_CATEGORY = "Custom Text"; //$NON-NLS-1$ /** * Custom XML label used internally and therefore should not be externalized */ public static final String CUSTOM_XML_CATEGORY = "Custom XML"; //$NON-NLS-1$ /** Default experiment type */ public static final String DEFAULT_EXPERIMENT_TYPE = "fr.inria.linuxtools.tmf.core.experiment.generic"; //$NON-NLS-1$ // The mapping of available trace type IDs to their corresponding // configuration element private static final Map<String, IConfigurationElement> TRACE_TYPE_ATTRIBUTES = new HashMap<>(); private static final Map<String, IConfigurationElement> TRACE_CATEGORIES = new HashMap<>(); private static final Map<String, TraceTypeHelper> TRACE_TYPES = new LinkedHashMap<>(); static { populateCategoriesAndTraceTypes(); populateCustomTraceTypes(); } /** * Enum to say whether a type applies to a trace or experiment * * @author Geneviève Bastien */ public enum TraceElementType { /** Trace type applies to trace */ TRACE, /** Trace type applies to experiment */ EXPERIMENT, } // ------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------ private TmfTraceType() { } // ------------------------------------------------------------------ // Operations // ------------------------------------------------------------------ /** * Retrieves the category name from the platform extension registry based on * the category ID * * @param categoryId * The category ID * @return the category name or empty string if not found */ public static String getCategoryName(String categoryId) { IConfigurationElement[] elements = Platform.getExtensionRegistry() .getConfigurationElementsFor(TMF_TRACE_TYPE_ID); for (IConfigurationElement element : elements) { if (element.getName().equals(CATEGORY_ELEM) && categoryId.equals(element.getAttribute(ID_ATTR))) { return element.getAttribute(NAME_ATTR); } } return ""; //$NON-NLS-1$ } /** * Retrieves all configuration elements from the platform extension registry * for the trace type extension that apply to traces and not experiments. * * @return an array of trace type configuration elements */ public static IConfigurationElement[] getTypeElements() { IConfigurationElement[] elements = Platform.getExtensionRegistry() .getConfigurationElementsFor(TMF_TRACE_TYPE_ID); List<IConfigurationElement> typeElements = new LinkedList<>(); for (IConfigurationElement element : elements) { if (element.getName().equals(TYPE_ELEM)) { typeElements.add(element); } } return typeElements.toArray(new IConfigurationElement[typeElements.size()]); } /** * Retrieve the TraceTypeHelper for a given trace type ID * * @param id * The trace type ID * @return The corresponding TraceTypeHelper, or null if there is none for * the specified ID */ public static TraceTypeHelper getTraceTypeHelper(String id) { return TRACE_TYPES.get(id); } /** * Get an iterable view of the existing trace type IDs. * * @return The currently registered trace type IDs */ public static Iterable<String> getTraceTypeIDs() { return TRACE_TYPES.keySet(); } /** * Get an iterable view of the existing trace type helpers. * * @return The currently registered trace type helpers */ public static Iterable<TraceTypeHelper> getTraceTypeHelpers() { return TRACE_TYPES.values(); } /** * Returns a list of "category:tracetype , ..." * * Returns only trace types, not experiment types * * @return returns a list of "category:tracetype , ..." */ public static String[] getAvailableTraceTypes() { return getAvailableTraceTypes(null); } /** * Returns a list of "category:tracetype , ..." sorted by given comparator. * * Returns only trace types, not experiment types * * @param comparator * Comparator class (type String) or null for alphabetical order. * @return sorted list according to the given comparator */ public static String[] getAvailableTraceTypes(Comparator<String> comparator) { // Generate the list of Category:TraceType to populate the ComboBox List<String> traceTypes = new ArrayList<>(); for (String key : TRACE_TYPES.keySet()) { TraceTypeHelper tt = TRACE_TYPES.get(key); if (!tt.isExperimentType()) { traceTypes.add(tt.getCategoryName() + SEPARATOR + tt.getName()); } } if (comparator == null) { Collections.sort(traceTypes); } else { Collections.sort(traceTypes, comparator); } // Format result return traceTypes.toArray(new String[traceTypes.size()]); } /** * Gets the custom trace types (custom text and friends) * * @param type * the type to get (Text, xml or other...) * @return the list of custom trace types */ public static List<String> getCustomTraceTypes(String type) { List<String> traceTypes = new ArrayList<>(); if (type.equals(CUSTOM_TXT_CATEGORY)) { for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) { String traceTypeName = def.definitionName; traceTypes.add(traceTypeName); } } if (type.equals(CUSTOM_XML_CATEGORY)) { for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) { String traceTypeName = def.definitionName; traceTypes.add(traceTypeName); } } return traceTypes; } /** * Gets all the custom trace types * * @return the list of custom trace types */ public static List<String> getCustomTraceTypes() { List<String> traceTypes = new ArrayList<>(); for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) { String traceTypeName = def.definitionName; traceTypes.add(traceTypeName); } for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) { String traceTypeName = def.definitionName; traceTypes.add(traceTypeName); } return traceTypes; } private static void populateCustomTraceTypes() { // add the custom trace types for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) { String traceTypeId = CustomTxtTrace.class.getCanonicalName() + SEPARATOR + def.definitionName; ITmfTrace trace = new CustomTxtTrace(def); TraceTypeHelper tt = new TraceTypeHelper(traceTypeId, CUSTOM_TXT_CATEGORY, def.definitionName, trace, false, TraceElementType.TRACE); TRACE_TYPES.put(traceTypeId, tt); // Deregister trace as signal handler because it is only used for validation TmfSignalManager.deregister(trace); } for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) { String traceTypeId = CustomXmlTrace.class.getCanonicalName() + SEPARATOR + def.definitionName; ITmfTrace trace = new CustomXmlTrace(def); TraceTypeHelper tt = new TraceTypeHelper(traceTypeId, CUSTOM_XML_CATEGORY, def.definitionName, trace, false, TraceElementType.TRACE); TRACE_TYPES.put(traceTypeId, tt); // Deregister trace as signal handler because it is only used for validation TmfSignalManager.deregister(trace); } } /** * Add or replace a custom trace type * * @param category * The custom parser category * @param definitionName * The custom parser definition name to add or replace */ public static void addCustomTraceType(String category, String definitionName) { String traceTypeId = null; ITmfTrace trace = null; if (category.equals(CUSTOM_TXT_CATEGORY)) { traceTypeId = CustomTxtTrace.class.getCanonicalName() + SEPARATOR + definitionName; CustomTxtTraceDefinition def = CustomTxtTraceDefinition.load(definitionName); if (def != null) { trace = new CustomTxtTrace(def); } } else if (category.equals(CUSTOM_XML_CATEGORY)) { traceTypeId = CustomXmlTrace.class.getCanonicalName() + SEPARATOR + definitionName; CustomXmlTraceDefinition def = CustomXmlTraceDefinition.load(definitionName); if (def != null) { trace = new CustomXmlTrace(def); } } if (traceTypeId != null && trace != null) { TraceTypeHelper helper = TRACE_TYPES.get(traceTypeId); if (helper != null) { helper.getTrace().dispose(); } TraceTypeHelper tt = new TraceTypeHelper(traceTypeId, category, definitionName, trace, false, TraceElementType.TRACE); TRACE_TYPES.put(traceTypeId, tt); // Deregister trace as signal handler because it is only used for validation TmfSignalManager.deregister(trace); } } /** * Remove a custom trace type * * @param category * The custom parser category * @param definitionName * The custom parser definition name to add or replace */ public static void removeCustomTraceType(String category, String definitionName) { if (category.equals(CUSTOM_TXT_CATEGORY)) { String traceTypeId = CustomTxtTrace.class.getCanonicalName() + SEPARATOR + definitionName; TraceTypeHelper helper = TRACE_TYPES.remove(traceTypeId); if (helper != null) { helper.getTrace().dispose(); } } else if (category.equals(CUSTOM_XML_CATEGORY)) { String traceTypeId = CustomXmlTrace.class.getCanonicalName() + SEPARATOR + definitionName; TraceTypeHelper helper = TRACE_TYPES.remove(traceTypeId); if (helper != null) { helper.getTrace().dispose(); } } } /** * Gets a trace type for a given canonical id * * @param id * the ID of the trace * @return the return type */ public static TraceTypeHelper getTraceType(String id) { return TRACE_TYPES.get(id); } private static void populateCategoriesAndTraceTypes() { if (TRACE_TYPES.isEmpty()) { // Populate the Categories and Trace Types IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType.TMF_TRACE_TYPE_ID); for (IConfigurationElement ce : config) { String elementName = ce.getName(); if (elementName.equals(TmfTraceType.TYPE_ELEM)) { String traceTypeId = ce.getAttribute(TmfTraceType.ID_ATTR); TRACE_TYPE_ATTRIBUTES.put(traceTypeId, ce); } else if (elementName.equals(TmfTraceType.CATEGORY_ELEM)) { String categoryId = ce.getAttribute(TmfTraceType.ID_ATTR); TRACE_CATEGORIES.put(categoryId, ce); } else if (elementName.equals(TmfTraceType.EXPERIMENT_ELEM)) { String experimentTypeId = ce.getAttribute(TmfTraceType.ID_ATTR); TRACE_TYPE_ATTRIBUTES.put(experimentTypeId, ce); } } // create the trace types for (String typeId : TRACE_TYPE_ATTRIBUTES.keySet()) { IConfigurationElement ce = TRACE_TYPE_ATTRIBUTES.get(typeId); final String category = getCategory(ce); final String attribute = ce.getAttribute(TmfTraceType.NAME_ATTR); ITmfTrace trace = null; TraceElementType elementType = TraceElementType.TRACE; try { if (ce.getName().equals(TmfTraceType.TYPE_ELEM)) { trace = (ITmfTrace) ce.createExecutableExtension(TmfTraceType.TRACE_TYPE_ATTR); } else if (ce.getName().equals(TmfTraceType.EXPERIMENT_ELEM)) { trace = (ITmfTrace) ce.createExecutableExtension(TmfTraceType.EXPERIMENT_TYPE_ATTR); elementType = TraceElementType.EXPERIMENT; } if (trace == null) { break; } // Deregister trace as signal handler because it is only // used for validation TmfSignalManager.deregister(trace); final String dirString = ce.getAttribute(TmfTraceType.IS_DIR_ATTR); boolean isDir = Boolean.parseBoolean(dirString); TraceTypeHelper tt = new TraceTypeHelper(typeId, category, attribute, trace, isDir, elementType); TRACE_TYPES.put(typeId, tt); } catch (CoreException e) { } } } } private static String getCategory(IConfigurationElement ce) { final String categoryId = ce.getAttribute(TmfTraceType.CATEGORY_ATTR); if (categoryId != null) { IConfigurationElement category = TRACE_CATEGORIES.get(categoryId); if (category != null && !category.getName().equals("")) { //$NON-NLS-1$ return category.getAttribute(TmfTraceType.NAME_ATTR); } } return "[no category]"; //$NON-NLS-1$ } /** * Returns the list of trace categories * * @return the list of trace categories */ public static List<String> getTraceCategories() { List<String> categoryNames = new ArrayList<>(); for (String key : TRACE_TYPES.keySet()) { final String categoryName = TRACE_TYPES.get(key).getCategoryName(); if (!categoryNames.contains(categoryName)) { categoryNames.add(categoryName); } } return categoryNames; } /** * Get the trace type helper classes from category name. Return only the * trace types, not the experiment types * * @param categoryName * the categoryName to lookup * @return a list of trace type helper classes {@link TraceTypeHelper} */ public static List<TraceTypeHelper> getTraceTypes(String categoryName) { List<TraceTypeHelper> traceNames = new ArrayList<>(); for (String key : TRACE_TYPES.keySet()) { if (!TRACE_TYPES.get(key).isExperimentType()) { final String storedCategoryName = TRACE_TYPES.get(key).getCategoryName(); if (storedCategoryName.equals(categoryName)) { traceNames.add(TRACE_TYPES.get(key)); } } } return traceNames; } /** * Validate a trace type * * @param traceTypeName * the trace category (canonical name) * @param fileName * the file name (and path) * @return true if the trace is of a valid type */ public static boolean validate(String traceTypeName, String fileName) { if (traceTypeName != null && !traceTypeName.isEmpty()) { final TraceTypeHelper traceTypeHelper = TRACE_TYPES.get(traceTypeName); if (traceTypeHelper == null || !traceTypeHelper.validate(fileName).isOK()) { return false; } } return true; } /** * Validate a trace * * @param traceToValidate * the trace category (canonical name) * @return true if the trace is of a valid type */ public static boolean validate(TraceValidationHelper traceToValidate) { return validate(traceToValidate.getTraceType(), traceToValidate.getTraceToScan()); } /** * Validate a list of files with a tracetype * * @param traceTypeName * the trace category (canonical name) * @param traces * the list of files to check if they are trace * @return true if all the traces are valid */ public static boolean validateTraceFiles(String traceTypeName, List<File> traces) { if (traceTypeName != null && !"".equals(traceTypeName) && //$NON-NLS-1$ !traceTypeName.startsWith(TmfTraceType.CUSTOM_TXT_CATEGORY) && !traceTypeName.startsWith(TmfTraceType.CUSTOM_XML_CATEGORY)) { for (File trace : traces) { if (!validate(traceTypeName, trace.getAbsolutePath())) { return false; } } } return true; } /** * Get a configuration element for a given name * * @param traceType * the name canonical * @return the configuration element, can be null */ public static IConfigurationElement getTraceAttributes(String traceType) { return TRACE_TYPE_ATTRIBUTES.get(traceType); } /** * Find the id of a trace type by its parameters * * @param category * like "ctf" or "custom text" * @param traceType * like "kernel" * @return an id like "fr.inria.linuxtools.blabla... */ public static String getTraceTypeId(String category, String traceType) { for (String key : TRACE_TYPES.keySet()) { if (TRACE_TYPES.get(key).getCategoryName().equals(category.trim()) && TRACE_TYPES.get(key).getName().equals(traceType.trim())) { return key; } } return null; } /** * Gets the custom trace type ID from the custom trace name * * @param traceType * The trace type in human form (category:name) * @return the trace type ID or null if the trace is not a custom one */ public static String getCustomTraceTypeId(String traceType) { String traceTypeId = null; // do custom trace stuff here String traceTypeToken[] = traceType.split(":", 2); //$NON-NLS-1$ if (traceTypeToken.length == 2) { final boolean startsWithTxt = traceType.startsWith(TmfTraceType.CUSTOM_TXT_CATEGORY); final boolean startsWithXML = traceType.startsWith(TmfTraceType.CUSTOM_XML_CATEGORY); if (startsWithTxt) { traceTypeId = CustomTxtTrace.class.getCanonicalName() + SEPARATOR + traceTypeToken[1]; } else if (startsWithXML) { traceTypeId = CustomXmlTrace.class.getCanonicalName() + SEPARATOR + traceTypeToken[1]; } } return traceTypeId; } /** * Is the trace a custom (user-defined) trace type. These are the traces * like : text and xml defined by the custom trace wizard. * * @param traceType * the trace type in human form (category:name) * @return true if the trace is a custom type */ public static boolean isCustomTrace(String traceType) { final boolean startsWithTxt = traceType.startsWith(TmfTraceType.CUSTOM_TXT_CATEGORY); final boolean startsWithXML = traceType.startsWith(TmfTraceType.CUSTOM_XML_CATEGORY); return (startsWithTxt || startsWithXML); } /** * Checks if a trace is a valid directory trace * @param path * the file name (and path) * @return <code>true</code> if the trace is a valid directory trace else <code>false</code> */ public static boolean isDirectoryTrace(String path) { final Iterable<TraceTypeHelper> traceTypeHelpers = getTraceTypeHelpers(); for (TraceTypeHelper traceTypeHelper : traceTypeHelpers) { if (traceTypeHelper.isDirectoryTraceType() && traceTypeHelper.validate(path).isOK()) { return true; } } return false; } /** * @param traceType * the trace type * @return <code>true</code> it is a directory trace type else else <code>false</code> */ public static boolean isDirectoryTraceType(String traceType) { if (traceType != null) { TraceTypeHelper traceTypeHelper = getTraceType(traceType); if (traceTypeHelper != null) { return traceTypeHelper.isDirectoryTraceType(); } } throw new IllegalArgumentException("Invalid trace type string: " + traceType); //$NON-NLS-1$ } }