tmf: Consolidate constructors in TmfExperiment
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / TmfTraceManager.java
CommitLineData
fc526aef 1/*******************************************************************************
be4a197a 2 * Copyright (c) 2013, 2014 Ericsson
fc526aef
AM
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 * Alexandre Montplaisir - Initial API and implementation
0fcf3b09 11 * Patrick Tasse - Support selection range
d3de0920 12 * Xavier Raynaud - Support filters tracking
fc526aef
AM
13 *******************************************************************************/
14
2bdf0193 15package org.eclipse.tracecompass.tmf.core.trace;
fc526aef 16
e1385db9 17import java.io.File;
3ec38c4c 18import java.net.URISyntaxException;
0f8687b4 19import java.util.Arrays;
fab18d20 20import java.util.Collections;
fc526aef 21import java.util.LinkedHashMap;
0f8687b4 22import java.util.LinkedHashSet;
fc526aef 23import java.util.Map;
fab18d20 24import java.util.Set;
fc526aef 25
deaae6e1 26import org.eclipse.core.resources.IFile;
b5e8ee95
GB
27import org.eclipse.core.resources.IFolder;
28import org.eclipse.core.resources.IProject;
e1385db9
AM
29import org.eclipse.core.resources.IResource;
30import org.eclipse.core.runtime.CoreException;
1ac53e54 31import org.eclipse.core.runtime.URIUtil;
0f8687b4 32import org.eclipse.jdt.annotation.NonNull;
2bdf0193
AM
33import org.eclipse.tracecompass.internal.tmf.core.Activator;
34import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
35import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
36import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal;
37import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
38import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
39import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
40import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
41import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
42import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
43import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
44import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
45import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
46import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
fc526aef
AM
47
48/**
49 * Central trace manager for TMF. It tracks the currently opened traces and
0fcf3b09 50 * experiment, as well as the currently-selected time or time range and the
d3de0920
XR
51 * current window time range for each one of those. It also tracks filters
52 * applied for each trace.
fc526aef
AM
53 *
54 * It's a singleton class, so only one instance should exist (available via
55 * {@link #getInstance()}).
56 *
57 * @author Alexandre Montplaisir
58 * @since 2.0
59 */
60public final class TmfTraceManager {
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
66 private final Map<ITmfTrace, TmfTraceContext> fTraces;
67
68 /** The currently-selected trace. Should always be part of the trace map */
69 private ITmfTrace fCurrentTrace = null;
70
3ec38c4c
MAL
71 private static final String TEMP_DIR_NAME = ".temp"; //$NON-NLS-1$
72
fc526aef
AM
73 // ------------------------------------------------------------------------
74 // Constructor
75 // ------------------------------------------------------------------------
76
77 private TmfTraceManager() {
a4524c1b 78 fTraces = new LinkedHashMap<>();
fc526aef
AM
79 TmfSignalManager.registerVIP(this);
80 }
81
82 /** Singleton instance */
83 private static TmfTraceManager tm = null;
84
85 /**
86 * Get an instance of the trace manager.
87 *
88 * @return The trace manager
89 */
90 public static synchronized TmfTraceManager getInstance() {
91 if (tm == null) {
92 tm = new TmfTraceManager();
93 }
94 return tm;
95 }
96
97 // ------------------------------------------------------------------------
98 // Accessors
99 // ------------------------------------------------------------------------
100
fc526aef 101 /**
0fcf3b09 102 * @return The begin timestamp of selection
4b121c48 103 * @since 2.1
0fcf3b09
PT
104 */
105 public ITmfTimestamp getSelectionBeginTime() {
106 return getCurrentTraceContext().getSelectionBegin();
107 }
108
109 /**
110 * @return The end timestamp of selection
4b121c48 111 * @since 2.1
0fcf3b09
PT
112 */
113 public ITmfTimestamp getSelectionEndTime() {
114 return getCurrentTraceContext().getSelectionEnd();
115 }
116
117 /**
118 * Return the current window time range.
fc526aef 119 *
0fcf3b09 120 * @return the current window time range
fc526aef
AM
121 */
122 public synchronized TmfTimeRange getCurrentRange() {
0fcf3b09 123 return getCurrentTraceContext().getWindowRange();
fc526aef
AM
124 }
125
d3de0920
XR
126 /**
127 * Gets the filter applied to the current trace
128 *
129 * @return
130 * a filter, or <code>null</code>
131 * @since 2.2
132 */
133 public synchronized ITmfFilter getCurrentFilter() {
134 return getCurrentTraceContext().getFilter();
135 }
136
fc526aef
AM
137 /**
138 * Get the currently selected trace (normally, the focused editor).
139 *
140 * @return The active trace
141 */
142 public synchronized ITmfTrace getActiveTrace() {
143 return fCurrentTrace;
144 }
145
146 /**
a6fc3a28 147 * Get the trace set of the currently active trace.
fc526aef
AM
148 *
149 * @return The active trace set
a6fc3a28 150 * @see #getTraceSet(ITmfTrace)
fc526aef
AM
151 */
152 public synchronized ITmfTrace[] getActiveTraceSet() {
153 final ITmfTrace trace = fCurrentTrace;
a6fc3a28 154 return getTraceSet(trace);
fc526aef
AM
155 }
156
fab18d20
AM
157 /**
158 * Get the currently-opened traces, as an unmodifiable set.
159 *
160 * @return A set containing the opened traces
161 */
162 public synchronized Set<ITmfTrace> getOpenedTraces() {
163 return Collections.unmodifiableSet(fTraces.keySet());
164 }
165
deaae6e1
PT
166 /**
167 * Get the editor file for an opened trace.
168 *
169 * @param trace
170 * the trace
171 * @return the editor file or null if the trace is not opened
172 * @since 3.0
173 */
174 public synchronized IFile getTraceEditorFile(ITmfTrace trace) {
175 TmfTraceContext ctx = fTraces.get(trace);
176 if (ctx != null) {
177 return ctx.getEditorFile();
178 }
179 return null;
180 }
181
fc526aef
AM
182 private TmfTraceContext getCurrentTraceContext() {
183 TmfTraceContext curCtx = fTraces.get(fCurrentTrace);
184 if (curCtx == null) {
185 /* There are no traces opened at the moment. */
186 return TmfTraceContext.NULL_CONTEXT;
187 }
188 return curCtx;
189 }
190
e1385db9
AM
191 // ------------------------------------------------------------------------
192 // Public utility methods
193 // ------------------------------------------------------------------------
194
a6fc3a28
AM
195 /**
196 * Get the trace set of a given trace. For a standard trace, this is simply
197 * an array with only that trace in it. For experiments, this is an array of
198 * all the traces contained in this experiment.
199 *
200 * @param trace
201 * The trace or experiment
202 * @return The corresponding trace set
203 */
204 public static ITmfTrace[] getTraceSet(ITmfTrace trace) {
205 if (trace == null) {
206 return null;
207 }
208 if (trace instanceof TmfExperiment) {
209 TmfExperiment exp = (TmfExperiment) trace;
210 return exp.getTraces();
211 }
212 return new ITmfTrace[] { trace };
213 }
214
0f8687b4
GB
215 /**
216 * Get the trace set of a given trace or experiment, including the
217 * experiment. For a standard trace, this is simply a set containing only
218 * that trace. For experiments, it is the set of all the traces contained in
219 * this experiment, along with the experiment.
220 *
221 * @param trace
222 * The trace or experiment
223 * @return The corresponding trace set, including the experiment
224 * @since 3.1
225 */
226 public static @NonNull Set<ITmfTrace> getTraceSetWithExperiment(ITmfTrace trace) {
227 if (trace == null) {
228 @SuppressWarnings("null")
229 @NonNull Set<ITmfTrace> emptySet = Collections.EMPTY_SET;
230 return emptySet;
231 }
232 if (trace instanceof TmfExperiment) {
233 TmfExperiment exp = (TmfExperiment) trace;
234 ITmfTrace[] traces = exp.getTraces();
235 Set<ITmfTrace> alltraces = new LinkedHashSet<>(Arrays.asList(traces));
236 alltraces.add(exp);
237 return alltraces;
238 }
239 @SuppressWarnings("null")
240 @NonNull Set<ITmfTrace> singleton = Collections.singleton(trace);
241 return singleton;
242 }
243
e1385db9
AM
244 /**
245 * Return the path (as a string) to the directory for supplementary files to
246 * use with a given trace. If no supplementary file directory has been
247 * configured, a temporary directory based on the trace's name will be
248 * provided.
249 *
250 * @param trace
251 * The trace
252 * @return The path to the supplementary file directory (trailing slash is
253 * INCLUDED!)
254 */
255 public static String getSupplementaryFileDir(ITmfTrace trace) {
256 IResource resource = trace.getResource();
257 if (resource == null) {
258 return getTemporaryDir(trace);
259 }
260
261 String supplDir = null;
262 try {
263 supplDir = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
264 } catch (CoreException e) {
265 return getTemporaryDir(trace);
266 }
267 return supplDir + File.separator;
268 }
269
b5e8ee95
GB
270 /**
271 * Refresh the supplementary files resources for a trace, so it can pick up
272 * new files that got created.
273 *
274 * @param trace
275 * The trace for which to refresh the supplementary files
276 * @since 3.0
277 */
278 public static void refreshSupplementaryFiles(ITmfTrace trace) {
279 IResource resource = trace.getResource();
88567ed2 280 if (resource != null && resource.exists()) {
b5e8ee95
GB
281 String supplFolderPath = getSupplementaryFileDir(trace);
282 IProject project = resource.getProject();
283 /* Remove the project's path from the supplementary path dir */
284 if (!supplFolderPath.startsWith(project.getLocationURI().getPath())) {
285 Activator.logWarning(String.format("Supplementary files folder for trace %s is not within the project.", trace.getName())); //$NON-NLS-1$
286 return;
287 }
288 IFolder supplFolder = project.getFolder(supplFolderPath.substring(project.getLocationURI().getPath().length()));
289 if (supplFolder.exists()) {
290 try {
291 supplFolder.refreshLocal(IResource.DEPTH_INFINITE, null);
292 } catch (CoreException e) {
293 Activator.logError("Error refreshing resources", e); //$NON-NLS-1$
294 }
295 }
296 }
297 }
298
fc526aef
AM
299 // ------------------------------------------------------------------------
300 // Signal handlers
301 // ------------------------------------------------------------------------
302
303 /**
304 * Signal handler for the traceOpened signal.
305 *
306 * @param signal
307 * The incoming signal
308 */
309 @TmfSignalHandler
310 public synchronized void traceOpened(final TmfTraceOpenedSignal signal) {
311 final ITmfTrace trace = signal.getTrace();
deaae6e1 312 final IFile editorFile = signal.getEditorFile();
fc526aef
AM
313 final ITmfTimestamp startTs = trace.getStartTime();
314
315 /* Calculate the initial time range */
316 final int SCALE = ITmfTimestamp.NANOSECOND_SCALE;
317 long offset = trace.getInitialRangeOffset().normalize(0, SCALE).getValue();
318 long endTime = startTs.normalize(0, SCALE).getValue() + offset;
319 final TmfTimeRange startTr = new TmfTimeRange(startTs, new TmfTimestamp(endTime, SCALE));
320
deaae6e1 321 final TmfTraceContext startCtx = new TmfTraceContext(startTs, startTs, startTr, editorFile);
fc526aef
AM
322
323 fTraces.put(trace, startCtx);
324
325 /* We also want to set the newly-opened trace as the active trace */
326 fCurrentTrace = trace;
327 }
328
329
330 /**
331 * Handler for the TmfTraceSelectedSignal.
332 *
333 * @param signal
334 * The incoming signal
335 */
336 @TmfSignalHandler
337 public synchronized void traceSelected(final TmfTraceSelectedSignal signal) {
338 final ITmfTrace newTrace = signal.getTrace();
339 if (!fTraces.containsKey(newTrace)) {
340 throw new RuntimeException();
341 }
342 fCurrentTrace = newTrace;
343 }
344
d3de0920
XR
345 /**
346 * Signal handler for the filterApplied signal.
347 *
348 * @param signal
349 * The incoming signal
350 * @since 2.2
351 */
352 @TmfSignalHandler
353 public synchronized void filterApplied(TmfEventFilterAppliedSignal signal) {
354 final ITmfTrace newTrace = signal.getTrace();
355 TmfTraceContext context = fTraces.get(newTrace);
356 if (context == null) {
357 throw new RuntimeException();
358 }
359 fTraces.put(newTrace, new TmfTraceContext(context, signal.getEventFilter()));
360 }
361
fc526aef
AM
362 /**
363 * Signal handler for the traceClosed signal.
364 *
365 * @param signal
366 * The incoming signal
367 */
368 @TmfSignalHandler
369 public synchronized void traceClosed(final TmfTraceClosedSignal signal) {
3fcf269e 370 fTraces.remove(signal.getTrace());
fc526aef
AM
371 if (fTraces.size() == 0) {
372 fCurrentTrace = null;
373 /*
374 * In other cases, we should receive a traceSelected signal that
375 * will indicate which trace is the new one.
376 */
377 }
378 }
379
380 /**
381 * Signal handler for the TmfTimeSynchSignal signal.
382 *
383 * The current time of *all* traces whose range contains the requested new
0fcf3b09 384 * selection time range will be updated.
fc526aef
AM
385 *
386 * @param signal
387 * The incoming signal
388 */
389 @TmfSignalHandler
390 public synchronized void timeUpdated(final TmfTimeSynchSignal signal) {
0fcf3b09
PT
391 final ITmfTimestamp beginTs = signal.getBeginTime();
392 final ITmfTimestamp endTs = signal.getEndTime();
fc526aef
AM
393
394 for (Map.Entry<ITmfTrace, TmfTraceContext> entry : fTraces.entrySet()) {
395 final ITmfTrace trace = entry.getKey();
0fcf3b09 396 if (beginTs.intersects(getValidTimeRange(trace)) || endTs.intersects(getValidTimeRange(trace))) {
fc526aef 397 TmfTraceContext prevCtx = entry.getValue();
0fcf3b09 398 TmfTraceContext newCtx = new TmfTraceContext(prevCtx, beginTs, endTs);
fc526aef
AM
399 entry.setValue(newCtx);
400 }
401 }
402 }
403
404 /**
405 * Signal handler for the TmfRangeSynchSignal signal.
406 *
0fcf3b09 407 * The current window time range of *all* valid traces will be updated
fc526aef
AM
408 * to the new requested times.
409 *
410 * @param signal
411 * The incoming signal
412 */
413 @TmfSignalHandler
414 public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal) {
fc526aef
AM
415 for (Map.Entry<ITmfTrace, TmfTraceContext> entry : fTraces.entrySet()) {
416 final ITmfTrace trace = entry.getKey();
417 final TmfTraceContext curCtx = entry.getValue();
418
419 final TmfTimeRange validTr = getValidTimeRange(trace);
420
fc526aef
AM
421 /* Determine the new time range */
422 TmfTimeRange targetTr = signal.getCurrentRange().getIntersection(validTr);
0fcf3b09 423 TmfTimeRange newTr = (targetTr == null ? curCtx.getWindowRange() : targetTr);
fc526aef
AM
424
425 /* Update the values */
0fcf3b09 426 TmfTraceContext newCtx = new TmfTraceContext(curCtx, newTr);
fc526aef
AM
427 entry.setValue(newCtx);
428 }
429 }
430
431 // ------------------------------------------------------------------------
e1385db9 432 // Private utility methods
fc526aef
AM
433 // ------------------------------------------------------------------------
434
435 /**
0fcf3b09
PT
436 * Return the valid time range of a trace (not the current window time
437 * range, but the range of all possible valid timestamps).
fc526aef
AM
438 *
439 * For a real trace this is the whole range of the trace. For an experiment,
440 * it goes from the start time of the earliest trace to the end time of the
441 * latest one.
442 *
443 * @param trace
444 * The trace to check for
445 * @return The valid time span, or 'null' if the trace is not valid
446 */
447 private TmfTimeRange getValidTimeRange(ITmfTrace trace) {
448 if (!fTraces.containsKey(trace)) {
449 /* Trace is not part of the currently opened traces */
450 return null;
451 }
452 if (!(trace instanceof TmfExperiment)) {
453 /* "trace" is a single trace, return its time range directly */
454 return trace.getTimeRange();
455 }
456 final ITmfTrace[] traces = ((TmfExperiment) trace).getTraces();
457 if (traces.length == 0) {
458 /* We are being trolled */
459 return null;
460 }
461 if (traces.length == 1) {
462 /* Trace is an experiment with only 1 trace */
463 return traces[0].getTimeRange();
464 }
465 /*
466 * Trace is an experiment with 2+ traces, so get the earliest start and
467 * the latest end.
468 */
469 ITmfTimestamp start = traces[0].getStartTime();
470 ITmfTimestamp end = traces[0].getEndTime();
471 for (int i = 1; i < traces.length; i++) {
472 ITmfTrace curTrace = traces[i];
473 if (curTrace.getStartTime().compareTo(start) < 0) {
474 start = curTrace.getStartTime();
475 }
476 if (curTrace.getEndTime().compareTo(end) > 0) {
477 end = curTrace.getEndTime();
478 }
479 }
480 return new TmfTimeRange(start, end);
481 }
e1385db9 482
3ec38c4c
MAL
483 /**
484 * Get the temporary directory path. If there is an instance of Eclipse
485 * running, the temporary directory will reside under the workspace.
486 *
487 * @return the temporary directory path suitable to be passed to the
488 * java.io.File constructor without a trailing separator
a465519a 489 * @since 3.2
3ec38c4c
MAL
490 */
491 public static String getTemporaryDirPath() {
492 // Get the workspace path from the properties
493 String property = System.getProperty("osgi.instance.area"); //$NON-NLS-1$
494 if (property != null) {
495 try {
1ac53e54 496 File dir = URIUtil.toFile(URIUtil.fromString(property));
3ec38c4c
MAL
497 dir = new File(dir.getAbsolutePath() + File.separator + TEMP_DIR_NAME);
498 if (!dir.exists()) {
499 dir.mkdirs();
500 }
501 return dir.getAbsolutePath();
502 } catch (URISyntaxException e) {
503 Activator.logError(e.getLocalizedMessage(), e);
504 }
505 }
506 return System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
507 }
508
e1385db9 509 /**
6e4358bd
AM
510 * Get a temporary directory based on a trace's name. We will create the
511 * directory if it doesn't exist, so that it's ready to be used.
e1385db9
AM
512 */
513 private static String getTemporaryDir(ITmfTrace trace) {
3ec38c4c 514 String pathName = getTemporaryDirPath() +
e1385db9
AM
515 File.separator +
516 trace.getName() +
517 File.separator;
6e4358bd
AM
518 File dir = new File(pathName);
519 if (!dir.exists()) {
520 dir.mkdirs();
521 }
522 return pathName;
e1385db9 523 }
fc526aef 524}
This page took 0.074196 seconds and 5 git commands to generate.