tmf: Fix Select Traces command does not refresh trace type
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / analysis / TmfAbstractAnalysisModule.java
CommitLineData
c068a752 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2013, 2014 École Polytechnique de Montréal
c068a752
GB
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.core.analysis;
14
15import java.util.ArrayList;
63c43609 16import java.util.Collections;
c068a752
GB
17import java.util.HashMap;
18import java.util.List;
19import java.util.Map;
20import java.util.concurrent.CountDownLatch;
21import java.util.concurrent.TimeUnit;
22
23import org.eclipse.core.runtime.IProgressMonitor;
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.core.runtime.jobs.Job;
dc58a1fb 27import org.eclipse.jdt.annotation.NonNull;
c068a752
GB
28import org.eclipse.linuxtools.internal.tmf.core.Activator;
29import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
30import org.eclipse.linuxtools.tmf.core.exceptions.TmfAnalysisException;
31import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
32import org.eclipse.linuxtools.tmf.core.signal.TmfStartAnalysisSignal;
33import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
34import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
9de979b2 35import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
c068a752
GB
36import org.eclipse.osgi.util.NLS;
37
38/**
39 * Base class that analysis modules main class may extend. It provides default
40 * behavior to some methods of the analysis module
41 *
42 * @author Geneviève Bastien
43 * @since 3.0
44 */
45public abstract class TmfAbstractAnalysisModule extends TmfComponent implements IAnalysisModule {
46
dc58a1fb
GB
47 @NonNull private static final String UNDEFINED_ID = "undefined"; //$NON-NLS-1$
48
c068a752
GB
49 private String fName, fId;
50 private boolean fAutomatic = false, fStarted = false;
51 private ITmfTrace fTrace;
a4524c1b
AM
52 private final Map<String, Object> fParameters = new HashMap<>();
53 private final List<String> fParameterNames = new ArrayList<>();
54 private final List<IAnalysisOutput> fOutputs = new ArrayList<>();
55 private List<IAnalysisParameterProvider> fParameterProviders = new ArrayList<>();
c068a752
GB
56 private Job fJob = null;
57
58 private final Object syncObj = new Object();
59
60 /* Latch tracking if the analysis is completed or not */
61 private CountDownLatch fFinishedLatch = new CountDownLatch(0);
62
63 private boolean fAnalysisCancelled = false;
64
65 @Override
66 public boolean isAutomatic() {
67 return fAutomatic;
68 }
69
70 @Override
71 public String getName() {
72 return fName;
73 }
74
75 @Override
76 public void setName(String name) {
77 fName = name;
78 }
79
80 @Override
81 public void setId(String id) {
82 fId = id;
83 }
84
85 @Override
dc58a1fb 86 @NonNull
c068a752 87 public String getId() {
dc58a1fb
GB
88 String id = fId;
89 if (id == null) {
90 Activator.logError("Analysis module getId(): the id should not be null in class " + this.getClass().getSimpleName()); //$NON-NLS-1$
91 return UNDEFINED_ID;
92 }
93 return id;
c068a752
GB
94 }
95
96 @Override
97 public void setAutomatic(boolean auto) {
98 fAutomatic = auto;
99 }
100
101 @Override
102 public void setTrace(ITmfTrace trace) throws TmfAnalysisException {
103 if (fTrace != null) {
104 throw new TmfAnalysisException(NLS.bind(Messages.TmfAbstractAnalysisModule_TraceSetMoreThanOnce, getName()));
105 }
106
107 /* Check that analysis can be executed */
108 if (!canExecute(trace)) {
109 throw new TmfAnalysisException(NLS.bind(Messages.TmfAbstractAnalysisModule_AnalysisCannotExecute, getName()));
110 }
111 fTrace = trace;
112 /* Get the parameter providers for this trace */
113 fParameterProviders = TmfAnalysisManager.getParameterProviders(this, fTrace);
114 for (IAnalysisParameterProvider provider : fParameterProviders) {
115 provider.registerModule(this);
116 }
117 resetAnalysis();
118 fStarted = false;
119 }
120
121 /**
122 * Gets the trace
123 *
124 * @return The trace
125 */
126 protected ITmfTrace getTrace() {
127 return fTrace;
128 }
129
130 @Override
131 public void addParameter(String name) {
132 fParameterNames.add(name);
133 }
134
135 @Override
136 public synchronized void setParameter(String name, Object value) {
137 if (!fParameterNames.contains(name)) {
138 throw new RuntimeException(NLS.bind(Messages.TmfAbstractAnalysisModule_InvalidParameter, name, getName()));
139 }
140 Object oldValue = fParameters.get(name);
141 fParameters.put(name, value);
142 if ((value != null) && !(value.equals(oldValue))) {
143 parameterChanged(name);
144 }
145 }
146
147 @Override
148 public synchronized void notifyParameterChanged(String name) {
149 if (!fParameterNames.contains(name)) {
150 throw new RuntimeException(NLS.bind(Messages.TmfAbstractAnalysisModule_InvalidParameter, name, getName()));
151 }
152 Object oldValue = fParameters.get(name);
153 Object value = getParameter(name);
154 if ((value != null) && !(value.equals(oldValue))) {
155 parameterChanged(name);
156 }
157 }
158
159 /**
160 * Used to indicate that a parameter value has been changed
161 *
162 * @param name
163 * The name of the modified parameter
164 */
165 protected void parameterChanged(String name) {
166
167 }
168
169 @Override
170 public Object getParameter(String name) {
171 Object paramValue = fParameters.get(name);
172 /* The parameter is not set, maybe it can be provided by someone else */
173 if ((paramValue == null) && (fTrace != null)) {
174 for (IAnalysisParameterProvider provider : fParameterProviders) {
175 paramValue = provider.getParameter(name);
176 if (paramValue != null) {
177 break;
178 }
179 }
180 }
181 return paramValue;
182 }
183
184 @Override
185 public boolean canExecute(ITmfTrace trace) {
186 return true;
187 }
188
189 /**
190 * Set the countdown latch back to 1 so the analysis can be executed again
191 */
192 protected void resetAnalysis() {
0d3a54a3 193 fFinishedLatch.countDown();
c068a752
GB
194 fFinishedLatch = new CountDownLatch(1);
195 }
196
197 /**
198 * Actually executes the analysis itself
199 *
200 * @param monitor
201 * Progress monitor
202 * @return Whether the analysis was completed successfully or not
203 * @throws TmfAnalysisException
204 * Method may throw an analysis exception
205 */
206 protected abstract boolean executeAnalysis(final IProgressMonitor monitor) throws TmfAnalysisException;
207
208 /**
209 * Indicate the analysis has been canceled. It is abstract to force
210 * implementing class to cleanup what they are running. This is called by
211 * the job's canceling. It does not need to be called directly.
212 */
213 protected abstract void canceling();
214
215 /**
216 * To be called when the analysis is completed, whether normally or because
217 * it was cancelled or for any other reason.
218 *
219 * It has to be called inside a synchronized block
220 */
221 private void setAnalysisCompleted() {
222 fStarted = false;
223 fJob = null;
224 fFinishedLatch.countDown();
9de979b2
GB
225 if (fTrace instanceof TmfTrace) {
226 ((TmfTrace) fTrace).refreshSupplementaryFiles();
227 }
c068a752
GB
228 }
229
230 /**
231 * Cancels the analysis if it is executing
232 */
233 @Override
234 public final void cancel() {
235 synchronized (syncObj) {
236 if (fJob != null) {
237 if (fJob.cancel()) {
238 fAnalysisCancelled = true;
239 setAnalysisCompleted();
240 }
241 }
242 fStarted = false;
243 }
244 }
245
130e6f4e
MAL
246 @Override
247 public void dispose() {
248 super.dispose();
249 cancel();
250 }
251
c068a752
GB
252 private void execute() {
253
254 /*
255 * TODO: The analysis in a job should be done at the analysis manager
256 * level instead of depending on this abstract class implementation,
257 * otherwise another analysis implementation may block the main thread
258 */
259
260 /* Do not execute if analysis has already run */
261 if (fFinishedLatch.getCount() == 0) {
262 return;
263 }
264
265 /* Do not execute if analysis already running */
266 synchronized (syncObj) {
267 if (fStarted) {
268 return;
269 }
270 fStarted = true;
271 }
272
273 /*
274 * Actual analysis will be run on a separate thread
275 */
276 fJob = new Job(NLS.bind(Messages.TmfAbstractAnalysisModule_RunningAnalysis, getName())) {
277 @Override
278 protected IStatus run(final IProgressMonitor monitor) {
279 try {
280 monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
281 broadcast(new TmfStartAnalysisSignal(TmfAbstractAnalysisModule.this, TmfAbstractAnalysisModule.this));
282 fAnalysisCancelled = !executeAnalysis(monitor);
283 } catch (TmfAnalysisException e) {
284 Activator.logError("Error executing analysis with trace " + getTrace().getName(), e); //$NON-NLS-1$
285 } finally {
286 synchronized (syncObj) {
287 monitor.done();
288 setAnalysisCompleted();
289 }
290 }
291 if (!fAnalysisCancelled) {
292 return Status.OK_STATUS;
293 }
baa96b1d
BH
294 // Reset analysis so that it can be executed again.
295 resetAnalysis();
c068a752
GB
296 return Status.CANCEL_STATUS;
297 }
298
299 @Override
300 protected void canceling() {
301 TmfAbstractAnalysisModule.this.canceling();
302 }
303
304 };
305 fJob.schedule();
306 }
307
308 @Override
309 public IStatus schedule() {
310 if (fTrace == null) {
311 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, String.format("No trace specified for analysis %s", getName())); //$NON-NLS-1$
312 }
313 execute();
314
315 return Status.OK_STATUS;
316 }
317
318 @Override
d9810555
AM
319 public Iterable<IAnalysisOutput> getOutputs() {
320 return fOutputs;
c068a752
GB
321 }
322
323 @Override
324 public void registerOutput(IAnalysisOutput output) {
325 if (!fOutputs.contains(output)) {
326 fOutputs.add(output);
327 }
328 }
329
7d6122fc
AM
330 @Override
331 public boolean waitForCompletion() {
332 try {
333 fFinishedLatch.await();
334 } catch (InterruptedException e) {
335 Activator.logError("Error while waiting for module completion", e); //$NON-NLS-1$
336 }
337 return !fAnalysisCancelled;
338 }
339
c068a752
GB
340 @Override
341 public boolean waitForCompletion(IProgressMonitor monitor) {
342 try {
0d3a54a3
AM
343 while (!fFinishedLatch.await(500, TimeUnit.MILLISECONDS)) {
344 if (fAnalysisCancelled || monitor.isCanceled()) {
c068a752
GB
345 fAnalysisCancelled = true;
346 return false;
347 }
348 }
349 } catch (InterruptedException e) {
350 Activator.logError("Error while waiting for module completion", e); //$NON-NLS-1$
351 }
352 return !fAnalysisCancelled;
353 }
354
355 /**
356 * Signal handler for trace closing
357 *
358 * @param signal
359 * Trace closed signal
360 */
361 @TmfSignalHandler
362 public void traceClosed(TmfTraceClosedSignal signal) {
363 /* Is the closing trace the one that was requested? */
364 if (signal.getTrace() == fTrace) {
365 cancel();
366 fTrace = null;
367 }
368 }
369
370 /**
371 * Returns a full help text to display
372 *
373 * @return Full help text for the module
374 */
375 protected String getFullHelpText() {
376 return NLS.bind(Messages.TmfAbstractAnalysisModule_AnalysisModule, getName());
377 }
378
379 /**
380 * Gets a short help text, to display as header to other help text
381 *
382 * @param trace
383 * The trace to show help for
384 *
385 * @return Short help text describing the module
386 */
387 protected String getShortHelpText(ITmfTrace trace) {
388 return NLS.bind(Messages.TmfAbstractAnalysisModule_AnalysisForTrace, getName(), trace.getName());
389 }
390
391 /**
392 * Gets the help text specific for a trace who does not have required
393 * characteristics for module to execute
394 *
395 * @param trace
396 * The trace to apply the analysis to
397 * @return Help text
398 */
399 protected String getTraceCannotExecuteHelpText(ITmfTrace trace) {
400 return Messages.TmfAbstractAnalysisModule_AnalysisCannotExecute;
401 }
402
403 @Override
404 public String getHelpText() {
405 return getFullHelpText();
406 }
407
408 @Override
409 public String getHelpText(ITmfTrace trace) {
410 if (trace == null) {
411 return getHelpText();
412 }
413 String text = getShortHelpText(trace);
414 if (!canExecute(trace)) {
415 text = text + getTraceCannotExecuteHelpText(trace);
416 }
417 return text;
418 }
419
63c43609
MR
420 @Override
421 public Iterable<TmfAnalysisRequirement> getAnalysisRequirements() {
422 return Collections.EMPTY_SET;
423 }
c068a752 424}
This page took 0.050382 seconds and 5 git commands to generate.