tmf.ui: fix potential priority inversion in symbol providers.
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / symbols / SymbolProviderManager.java
CommitLineData
d90ae2a5
RK
1/*******************************************************************************
2 * Copyright (c) 2016 Movidius Inc. and others
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 *******************************************************************************/
10
11package org.eclipse.tracecompass.tmf.ui.symbols;
12
13import java.lang.ref.WeakReference;
14import java.util.ArrayList;
15import java.util.Comparator;
16import java.util.List;
17import java.util.Map;
18import java.util.WeakHashMap;
19
20import org.eclipse.core.runtime.CoreException;
21import org.eclipse.core.runtime.IConfigurationElement;
22import org.eclipse.core.runtime.Platform;
23import org.eclipse.jdt.annotation.NonNull;
24import org.eclipse.tracecompass.internal.tmf.ui.Activator;
25import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
26
a54f9c9d
MK
27import com.google.common.collect.ImmutableList;
28
d90ae2a5
RK
29/**
30 * This class offer services around the
31 * <code>org.eclipse.tracecompass.tmf.ui.symbolProvider</code> extension point.
32 *
33 * @author Robert Kiss
34 * @since 2.0
35 *
36 */
37public final class SymbolProviderManager {
38
39 /**
40 * The singleton instance of this manager
41 */
42 private static SymbolProviderManager INSTANCE;
43
44 private static final String EXTENSION_POINT_ID = "org.eclipse.tracecompass.tmf.ui.symbolProvider"; //$NON-NLS-1$
45 private static final String ELEM_NAME_PROVIDER = "providerFactory"; //$NON-NLS-1$
46 private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
47 private static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
48
49 private final List<SymbolProviderFactoryWrapper> fProviders;
50
51 private final Map<ITmfTrace, WeakReference<ISymbolProvider>> fInstances = new WeakHashMap<>();
52
53 /**
54 * Internal class used to store extension point information
55 *
56 */
57 private static class SymbolProviderFactoryWrapper {
58
59 public final ISymbolProviderFactory factory;
60 public final int priority;
61
62 private SymbolProviderFactoryWrapper(ISymbolProviderFactory factory, int priority) {
63 this.factory = factory;
64 this.priority = priority;
65
66 }
67
68 }
69
70 /**
a54f9c9d 71 * Get the instance of the {@link SymbolProviderManager}
d90ae2a5
RK
72 * @return the singleton instance of this class
73 */
74 @SuppressWarnings("null")
75 public static synchronized @NonNull SymbolProviderManager getInstance() {
76 if (INSTANCE == null) {
a54f9c9d
MK
77 List<@NonNull SymbolProviderFactoryWrapper> providers = new ArrayList<>();
78 IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
79 for (IConfigurationElement element : configElements) {
80 if (ELEM_NAME_PROVIDER.equals(element.getName())) {
81 try {
82 Object extension = element.createExecutableExtension(ATTR_CLASS);
83 int priority = 0;
84 try {
85 priority = Integer.parseInt(element.getAttribute(ATTR_PRIORITY));
86 } catch (NumberFormatException e) {
87 // safe to ignore
88 }
89 providers.add(new SymbolProviderFactoryWrapper((ISymbolProviderFactory) extension, priority));
90 } catch (CoreException | ClassCastException e) {
91 Activator.getDefault().logError("Exception while loading extensions", e); //$NON-NLS-1$
92 }
93 }
94 }
95 /*
96 * Those with a higher priority need to be on top
97 *
98 * Note: we cannot simply sort by negative priority because
99 * (-Long.MIN_VAL) == Long.MIN_VAL
100 */
101 providers.sort(Comparator.<SymbolProviderFactoryWrapper> comparingLong(o -> o.priority).reversed());
102 INSTANCE = new SymbolProviderManager(providers);
d90ae2a5
RK
103 }
104 return INSTANCE;
105 }
106
107 /**
108 * The private constructor of this manager
109 */
a54f9c9d
MK
110 private SymbolProviderManager(@NonNull List<@NonNull SymbolProviderFactoryWrapper> providers) {
111 fProviders = ImmutableList.copyOf(providers);
d90ae2a5
RK
112 }
113
114 /**
115 * Locate an {@link ISymbolProvider} capable to resolve symbols from the
116 * given trace. If no such provider is defined an instance of
117 * {@link DefaultSymbolProvider} will be returned
118 *
119 * @param trace
120 * The trace to create a provider for
121 * @return a valid {@link ISymbolProvider}, never null
122 */
123 public @NonNull ISymbolProvider getSymbolProvider(@NonNull ITmfTrace trace) {
124 // Check to see if we already have a provider for this trace
125 synchronized (fInstances) {
126 WeakReference<ISymbolProvider> reference = fInstances.get(trace);
127 if (reference != null) {
128 ISymbolProvider provider = reference.get();
129 if (provider != null) {
130 return provider;
131 }
132 }
133 // we don't have yet an instance, build one
134 for (SymbolProviderFactoryWrapper wrapper : fProviders) {
135 ISymbolProviderFactory factory = wrapper.factory;
136 ISymbolProvider provider = factory.createProvider(trace);
137 if (provider != null) {
138 fInstances.put(trace, new WeakReference<>(provider));
139 return provider;
140 }
141 }
142 }
143 // No provider found, return the default one
144 return new DefaultSymbolProvider(trace);
145 }
146
147}
This page took 0.036894 seconds and 5 git commands to generate.