blob: 8a448faa7d746a0da46c85e87af3efeeefca42f0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 Movidius Inc. and others
*
* 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
* Robert Kiss - Initial API and implementation
* Mikael Ferland - Support multiple symbol providers for a trace
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.symbols;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
/**
* This class offer services around the
* <code>org.eclipse.tracecompass.tmf.core.symbolProvider</code> extension
* point.
*
* @author Robert Kiss
* @since 3.0
*/
public final class SymbolProviderManager {
/**
* The singleton instance of this manager
*/
private static @Nullable SymbolProviderManager INSTANCE;
private static final String OLD_EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.ui.symbolProvider"; //$NON-NLS-1$
private static final String EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.core.symbolProvider"; //$NON-NLS-1$
private static final String ELEM_NAME_PROVIDER = "providerFactory"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
private final List<SymbolProviderFactoryWrapper> fProviders;
private final Multimap<ITmfTrace, WeakReference<ISymbolProvider>> fInstances = LinkedHashMultimap.create();
/**
* Internal class used to store extension point information
*
*/
private static class SymbolProviderFactoryWrapper {
public final ISymbolProviderFactory factory;
public final int priority;
private SymbolProviderFactoryWrapper(ISymbolProviderFactory factory, int priority) {
this.factory = factory;
this.priority = priority;
}
}
/**
*
* @return the singleton instance of this class
*/
public static synchronized SymbolProviderManager getInstance() {
SymbolProviderManager manager = INSTANCE;
if (manager == null) {
manager = new SymbolProviderManager();
INSTANCE = manager;
}
return manager;
}
/**
* Dispose the singleton instance if it exists
*
* @since 3.3
*/
public static synchronized void dispose() {
SymbolProviderManager manager = INSTANCE;
if (manager != null) {
TmfSignalManager.deregister(manager);
manager.fProviders.clear();
manager.fInstances.clear();
}
INSTANCE = null;
}
/**
* The private constructor of this manager
*/
private SymbolProviderManager() {
fProviders = new ArrayList<>();
load(OLD_EXTENSION_POINT_ID);
load(EXTENSION_POINT_ID);
// Those with a higher priority need to be on top
fProviders.sort(Comparator.comparingLong(o -> -o.priority));
TmfSignalManager.register(this);
}
private void load(String configElemPath) {
IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(configElemPath);
for (IConfigurationElement element : configElements) {
if (element != null && ELEM_NAME_PROVIDER.equals(element.getName())) {
try {
Object extension = checkNotNull(element.createExecutableExtension(ATTR_CLASS));
int priority = 0;
try {
priority = Integer.parseInt(element.getAttribute(ATTR_PRIORITY));
} catch (NumberFormatException e) {
// safe to ignore
}
fProviders.add(new SymbolProviderFactoryWrapper((ISymbolProviderFactory) extension, priority));
} catch (CoreException | ClassCastException e) {
Activator.logError("Exception while loading extensions", e); //$NON-NLS-1$
}
}
}
}
/**
* Locate the {@link ISymbolProvider}s capable of resolving symbols from the
* given trace. If no such provider(s) are defined, a collection containing
* an instance of {@link DefaultSymbolProvider} will be returned
*
* @param trace
* The trace to create a provider for
* @return The collection of symbol providers for this trace. It will
* contain at least one valid {@link ISymbolProvider}.
*/
public Collection<ISymbolProvider> getSymbolProviders(ITmfTrace trace) {
synchronized (fInstances) {
Collection<ISymbolProvider> symbolProviders = new ArrayList<>();
// Verify if there are already provider(s) for this trace
for (WeakReference<ISymbolProvider> reference : fInstances.get(trace)) {
ISymbolProvider provider = reference.get();
if (provider != null) {
symbolProviders.add(provider);
}
}
// Build the appropriate provider(s)
if (symbolProviders.isEmpty()) {
for (ITmfTrace subTrace : TmfTraceManager.getTraceSet(trace)) {
// Not the same trace, so get the sub trace's symbol providers
if (subTrace != trace) {
Collection<ISymbolProvider> traceSymbolProviders = getSymbolProviders(subTrace);
traceSymbolProviders.forEach(sp -> {
symbolProviders.add(sp);
fInstances.put(trace, new WeakReference<>(sp));
});
} else {
// Create the symbol providers for this trace
for (SymbolProviderFactoryWrapper wrapper : fProviders) {
ISymbolProviderFactory factory = wrapper.factory;
ISymbolProvider provider = factory.createProvider(trace);
if (provider != null) {
symbolProviders.add(provider);
fInstances.put(trace, new WeakReference<>(provider));
}
}
}
}
}
// Build the default provider if required
if (symbolProviders.isEmpty()) {
DefaultSymbolProvider defaultSymbolProvider = new DefaultSymbolProvider(trace);
fInstances.put(trace, new WeakReference<>(defaultSymbolProvider));
symbolProviders.add(defaultSymbolProvider);
}
return symbolProviders;
}
}
/**
* Signal handler for the traceClosed signal.
*
* @param signal
* The incoming signal
* @since 3.3
*/
@TmfSignalHandler
public synchronized void traceClosed(final TmfTraceClosedSignal signal) {
for (ITmfTrace trace : TmfTraceManager.getTraceSet(signal.getTrace())) {
fInstances.removeAll(trace);
}
}
}