/******************************************************************************* * Copyright (c) 2016 Movidius Inc. and others * * 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 * *******************************************************************************/ package org.eclipse.tracecompass.tmf.ui.symbols; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.internal.tmf.ui.Activator; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import com.google.common.collect.ImmutableList; /** * This class offer services around the * <code>org.eclipse.tracecompass.tmf.ui.symbolProvider</code> extension point. * * @author Robert Kiss * @since 2.0 * */ public final class SymbolProviderManager { /** * The singleton instance of this manager */ private static SymbolProviderManager INSTANCE; private static final String EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.ui.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 Map<ITmfTrace, WeakReference<ISymbolProvider>> fInstances = new WeakHashMap<>(); /** * 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; } } /** * Get the instance of the {@link SymbolProviderManager} * @return the singleton instance of this class */ @SuppressWarnings("null") public static synchronized @NonNull SymbolProviderManager getInstance() { if (INSTANCE == null) { List<@NonNull SymbolProviderFactoryWrapper> providers = new ArrayList<>(); IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); for (IConfigurationElement element : configElements) { if (ELEM_NAME_PROVIDER.equals(element.getName())) { try { Object extension = element.createExecutableExtension(ATTR_CLASS); int priority = 0; try { priority = Integer.parseInt(element.getAttribute(ATTR_PRIORITY)); } catch (NumberFormatException e) { // safe to ignore } providers.add(new SymbolProviderFactoryWrapper((ISymbolProviderFactory) extension, priority)); } catch (CoreException | ClassCastException e) { Activator.getDefault().logError("Exception while loading extensions", e); //$NON-NLS-1$ } } } /* * Those with a higher priority need to be on top * * Note: we cannot simply sort by negative priority because * (-Integer.MIN_VAL) == Integer.MIN_VAL */ providers.sort(Comparator.<SymbolProviderFactoryWrapper> comparingInt(o -> o.priority).reversed()); INSTANCE = new SymbolProviderManager(providers); } return INSTANCE; } /** * The private constructor of this manager */ private SymbolProviderManager(@NonNull List<@NonNull SymbolProviderFactoryWrapper> providers) { fProviders = ImmutableList.copyOf(providers); } /** * Locate an {@link ISymbolProvider} capable to resolve symbols from the * given trace. If no such provider is defined an instance of * {@link DefaultSymbolProvider} will be returned * * @param trace * The trace to create a provider for * @return a valid {@link ISymbolProvider}, never null */ public @NonNull ISymbolProvider getSymbolProvider(@NonNull ITmfTrace trace) { // Check to see if we already have a provider for this trace synchronized (fInstances) { WeakReference<ISymbolProvider> reference = fInstances.get(trace); if (reference != null) { ISymbolProvider provider = reference.get(); if (provider != null) { return provider; } } // we don't have yet an instance, build one for (SymbolProviderFactoryWrapper wrapper : fProviders) { ISymbolProviderFactory factory = wrapper.factory; ISymbolProvider provider = factory.createProvider(trace); if (provider != null) { fInstances.put(trace, new WeakReference<>(provider)); return provider; } } } // No provider found, return the default one return new DefaultSymbolProvider(trace); } }