| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |