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