blob: 0ee9da6a7f314433258a039dc92430a856524f99 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2014 É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 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Geneviève Bastien - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.analysis;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.internal.tmf.core.analysis.TmfAnalysisModuleSources;
import org.eclipse.tracecompass.internal.tmf.core.analysis.TmfAnalysisParameterProviders;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
/**
* Manages the available analysis helpers from different sources and their
* parameter providers.
*
* @author Geneviève Bastien
*/
@NonNullByDefault
public class TmfAnalysisManager {
private static final Multimap<String, IAnalysisModuleHelper> fAnalysisModules = HashMultimap.create();
private static final Map<String, List<Class<? extends IAnalysisParameterProvider>>> fParameterProviders = new HashMap<>();
private static final Map<Class<? extends IAnalysisParameterProvider>, IAnalysisParameterProvider> fParamProviderInstances = new HashMap<>();
private static final List<IAnalysisModuleSource> fSources = new ArrayList<>();
private static final List<ITmfNewAnalysisModuleListener> fListeners = new ArrayList<>();
/**
* Constructor, not to be used
*/
private TmfAnalysisManager() {
}
/**
* Disposes the analysis manager
*
* @since 2.3
*/
public static void dispose() {
TmfAnalysisParameterProviders.dispose();
synchronized (fParameterProviders) {
fParamProviderInstances.values().forEach(provider -> provider.dispose());
}
}
/**
* Registers a new source of modules
*
* @param source
* A {@link IAnalysisModuleSource} instance
*/
public static synchronized void registerModuleSource(IAnalysisModuleSource source) {
fSources.add(source);
refreshModules();
}
/**
* Initializes sources and new module listeners from the extension point
*/
public static synchronized void initialize() {
fSources.clear();
fListeners.clear();
initializeModuleSources();
initializeNewModuleListeners();
}
/**
* Cleans the module sources list and initialize it from the extension point
*/
private static synchronized void initializeModuleSources() {
for (IAnalysisModuleSource source : TmfAnalysisModuleSources.getSources()) {
fSources.add(source);
}
}
/**
* Cleans the new module listeners list and initialize it from the extension
* point
*/
private static synchronized void initializeNewModuleListeners() {
for (ITmfNewAnalysisModuleListener output : TmfAnalysisModuleOutputs.getOutputListeners()) {
fListeners.add(output);
}
}
/**
* Add a new module listener to the list of listeners
*
* @param listener
* The new module listener
*/
public static synchronized void addNewModuleListener(ITmfNewAnalysisModuleListener listener) {
fListeners.add(listener);
}
/**
* Gets all available analysis module helpers
*
* This map is read-only
*
* @return The map of available {@link IAnalysisModuleHelper}
* @since 1.0
*/
public static synchronized Multimap<String, IAnalysisModuleHelper> getAnalysisModules() {
if (fAnalysisModules.isEmpty()) {
for (IAnalysisModuleSource source : fSources) {
for (IAnalysisModuleHelper helper : source.getAnalysisModules()) {
fAnalysisModules.put(helper.getId(), helper);
}
}
}
return checkNotNull(ImmutableMultimap.copyOf(fAnalysisModules));
}
/**
* Gets all analysis module helpers that apply to a given trace type. For
* each analysis ID, only one helper will be returned if more than one
* applies.
*
* This map is read-only
*
* TODO: This method is only used to populate the project view in the UI. It
* should be deprecated eventually, after some UI rework, so that the trace
* type does not drive whether the analysis module applies or not to a
* trace, but rather the content of the trace or experiment (once it is
* opened)
*
* @param traceclass
* The trace class to get modules for
* @return The map of available {@link IAnalysisModuleHelper}
*/
public static Map<String, IAnalysisModuleHelper> getAnalysisModules(Class<? extends ITmfTrace> traceclass) {
Multimap<String, IAnalysisModuleHelper> allModules = getAnalysisModules();
Map<String, IAnalysisModuleHelper> map = new HashMap<>();
for (IAnalysisModuleHelper module : allModules.values()) {
if (module.appliesToTraceType(traceclass)) {
map.put(module.getId(), module);
}
}
return ImmutableMap.copyOf(map);
}
/**
* Register a new parameter provider for an analysis
*
* @param analysisId
* The id of the analysis
* @param paramProvider
* The class of the parameter provider
*/
public static void registerParameterProvider(String analysisId, Class<? extends IAnalysisParameterProvider> paramProvider) {
synchronized (fParameterProviders) {
if (!fParameterProviders.containsKey(analysisId)) {
fParameterProviders.put(analysisId, new ArrayList<Class<? extends IAnalysisParameterProvider>>());
}
/* We checked via containsKey() above, get() should not return null */
checkNotNull(fParameterProviders.get(analysisId)).add(paramProvider);
}
}
/**
* Get the parameter providers that apply to the requested trace
*
* @param module
* Analysis module
* @param trace
* The trace
* @return The set of parameter providers that apply to a trace for this module
* @since 2.0
*/
public static Set<IAnalysisParameterProvider> getParameterProvidersForModule(IAnalysisModule module, ITmfTrace trace) {
/* First, get the parameter providers from the extension point */
Set<IAnalysisParameterProvider> providerSet = TmfAnalysisParameterProviders.getParameterProvidersFor(module.getId());
/* Then add any new parameter provider coming from other sources */
synchronized (fParameterProviders) {
if (!fParameterProviders.containsKey(module.getId())) {
return providerSet;
}
/* We checked via containsKey, get() should not return null */
List<Class<? extends IAnalysisParameterProvider>> parameterProviders = checkNotNull(fParameterProviders.get(module.getId()));
for (Class<? extends IAnalysisParameterProvider> providerClass : parameterProviders) {
try {
@Nullable IAnalysisParameterProvider provider = fParamProviderInstances.get(providerClass);
if (provider == null) {
provider = providerClass.getConstructor().newInstance();
fParamProviderInstances.put(providerClass, provider);
}
if (provider.appliesToTrace(trace)) {
providerSet.add(provider);
}
} catch (IllegalArgumentException | SecurityException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
Activator.logError(Messages.TmfAnalysisManager_ErrorParameterProvider, e);
}
}
}
return Collections.unmodifiableSet(providerSet);
}
/**
* Clear the list of modules so that next time, it is computed again from
* sources
*/
public static synchronized void refreshModules() {
fAnalysisModules.clear();
}
/**
* This method should be called when new analysis modules have been created
* by module helpers to that the {@link ITmfNewAnalysisModuleListener} can
* be executed on the module instance.
*
* @param module
* The newly created analysis module
*/
public static synchronized void analysisModuleCreated(IAnalysisModule module) {
for (ITmfNewAnalysisModuleListener listener : fListeners) {
listener.moduleCreated(module);
}
}
}