1 /*******************************************************************************
2 * Copyright (c) 2013 Ericsson
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
10 * Alexandre Montplaisir - Initial API and implementation
11 * Patrick Tasse - Support selection range
12 * Xavier Raynaud - Support filters tracking
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
18 import java
.util
.Collections
;
19 import java
.util
.LinkedHashMap
;
23 import org
.eclipse
.core
.resources
.IResource
;
24 import org
.eclipse
.core
.runtime
.CoreException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.filter
.ITmfFilter
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfEventFilterAppliedSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
40 * Central trace manager for TMF. It tracks the currently opened traces and
41 * experiment, as well as the currently-selected time or time range and the
42 * current window time range for each one of those. It also tracks filters
43 * applied for each trace.
45 * It's a singleton class, so only one instance should exist (available via
46 * {@link #getInstance()}).
48 * @author Alexandre Montplaisir
51 public final class TmfTraceManager
{
53 // ------------------------------------------------------------------------
55 // ------------------------------------------------------------------------
57 private final Map
<ITmfTrace
, TmfTraceContext
> fTraces
;
59 /** The currently-selected trace. Should always be part of the trace map */
60 private ITmfTrace fCurrentTrace
= null;
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
66 private TmfTraceManager() {
67 fTraces
= new LinkedHashMap
<>();
68 TmfSignalManager
.registerVIP(this);
71 /** Singleton instance */
72 private static TmfTraceManager tm
= null;
75 * Get an instance of the trace manager.
77 * @return The trace manager
79 public static synchronized TmfTraceManager
getInstance() {
81 tm
= new TmfTraceManager();
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
91 * Return the current selected time.
93 * @return the current time stamp
94 * @deprecated As of 2.1, use {@link #getSelectionBeginTime()} and {@link #getSelectionEndTime()}
97 public synchronized ITmfTimestamp
getCurrentTime() {
98 return getCurrentTraceContext().getSelectionBegin();
102 * @return The begin timestamp of selection
105 public ITmfTimestamp
getSelectionBeginTime() {
106 return getCurrentTraceContext().getSelectionBegin();
110 * @return The end timestamp of selection
113 public ITmfTimestamp
getSelectionEndTime() {
114 return getCurrentTraceContext().getSelectionEnd();
118 * Return the current window time range.
120 * @return the current window time range
122 public synchronized TmfTimeRange
getCurrentRange() {
123 return getCurrentTraceContext().getWindowRange();
127 * Gets the filter applied to the current trace
130 * a filter, or <code>null</code>
133 public synchronized ITmfFilter
getCurrentFilter() {
134 return getCurrentTraceContext().getFilter();
138 * Get the currently selected trace (normally, the focused editor).
140 * @return The active trace
142 public synchronized ITmfTrace
getActiveTrace() {
143 return fCurrentTrace
;
147 * Get the trace set of the currently active trace.
149 * @return The active trace set
150 * @see #getTraceSet(ITmfTrace)
152 public synchronized ITmfTrace
[] getActiveTraceSet() {
153 final ITmfTrace trace
= fCurrentTrace
;
154 return getTraceSet(trace
);
158 * Get the currently-opened traces, as an unmodifiable set.
160 * @return A set containing the opened traces
162 public synchronized Set
<ITmfTrace
> getOpenedTraces() {
163 return Collections
.unmodifiableSet(fTraces
.keySet());
166 private TmfTraceContext
getCurrentTraceContext() {
167 TmfTraceContext curCtx
= fTraces
.get(fCurrentTrace
);
168 if (curCtx
== null) {
169 /* There are no traces opened at the moment. */
170 return TmfTraceContext
.NULL_CONTEXT
;
175 // ------------------------------------------------------------------------
176 // Public utility methods
177 // ------------------------------------------------------------------------
180 * Get the trace set of a given trace. For a standard trace, this is simply
181 * an array with only that trace in it. For experiments, this is an array of
182 * all the traces contained in this experiment.
185 * The trace or experiment
186 * @return The corresponding trace set
188 public static ITmfTrace
[] getTraceSet(ITmfTrace trace
) {
192 if (trace
instanceof TmfExperiment
) {
193 TmfExperiment exp
= (TmfExperiment
) trace
;
194 return exp
.getTraces();
196 return new ITmfTrace
[] { trace
};
200 * Return the path (as a string) to the directory for supplementary files to
201 * use with a given trace. If no supplementary file directory has been
202 * configured, a temporary directory based on the trace's name will be
207 * @return The path to the supplementary file directory (trailing slash is
210 public static String
getSupplementaryFileDir(ITmfTrace trace
) {
211 IResource resource
= trace
.getResource();
212 if (resource
== null) {
213 return getTemporaryDir(trace
);
216 String supplDir
= null;
218 supplDir
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
219 } catch (CoreException e
) {
220 return getTemporaryDir(trace
);
222 return supplDir
+ File
.separator
;
225 // ------------------------------------------------------------------------
227 // ------------------------------------------------------------------------
230 * Signal handler for the traceOpened signal.
233 * The incoming signal
236 public synchronized void traceOpened(final TmfTraceOpenedSignal signal
) {
237 final ITmfTrace trace
= signal
.getTrace();
238 final ITmfTimestamp startTs
= trace
.getStartTime();
240 /* Calculate the initial time range */
241 final int SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
242 long offset
= trace
.getInitialRangeOffset().normalize(0, SCALE
).getValue();
243 long endTime
= startTs
.normalize(0, SCALE
).getValue() + offset
;
244 final TmfTimeRange startTr
= new TmfTimeRange(startTs
, new TmfTimestamp(endTime
, SCALE
));
246 final TmfTraceContext startCtx
= new TmfTraceContext(startTs
, startTs
, startTr
);
248 fTraces
.put(trace
, startCtx
);
250 /* We also want to set the newly-opened trace as the active trace */
251 fCurrentTrace
= trace
;
256 * Handler for the TmfTraceSelectedSignal.
259 * The incoming signal
262 public synchronized void traceSelected(final TmfTraceSelectedSignal signal
) {
263 final ITmfTrace newTrace
= signal
.getTrace();
264 if (!fTraces
.containsKey(newTrace
)) {
265 throw new RuntimeException();
267 fCurrentTrace
= newTrace
;
271 * Signal handler for the filterApplied signal.
274 * The incoming signal
278 public synchronized void filterApplied(TmfEventFilterAppliedSignal signal
) {
279 final ITmfTrace newTrace
= signal
.getTrace();
280 TmfTraceContext context
= fTraces
.get(newTrace
);
281 if (context
== null) {
282 throw new RuntimeException();
284 fTraces
.put(newTrace
, new TmfTraceContext(context
, signal
.getEventFilter()));
288 * Signal handler for the traceClosed signal.
291 * The incoming signal
294 public synchronized void traceClosed(final TmfTraceClosedSignal signal
) {
295 fTraces
.remove(signal
.getTrace());
296 if (fTraces
.size() == 0) {
297 fCurrentTrace
= null;
299 * In other cases, we should receive a traceSelected signal that
300 * will indicate which trace is the new one.
306 * Signal handler for the TmfTimeSynchSignal signal.
308 * The current time of *all* traces whose range contains the requested new
309 * selection time range will be updated.
312 * The incoming signal
315 public synchronized void timeUpdated(final TmfTimeSynchSignal signal
) {
316 final ITmfTimestamp beginTs
= signal
.getBeginTime();
317 final ITmfTimestamp endTs
= signal
.getEndTime();
319 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
320 final ITmfTrace trace
= entry
.getKey();
321 if (beginTs
.intersects(getValidTimeRange(trace
)) || endTs
.intersects(getValidTimeRange(trace
))) {
322 TmfTraceContext prevCtx
= entry
.getValue();
323 TmfTraceContext newCtx
= new TmfTraceContext(prevCtx
, beginTs
, endTs
);
324 entry
.setValue(newCtx
);
330 * Signal handler for the TmfRangeSynchSignal signal.
332 * The current window time range of *all* valid traces will be updated
333 * to the new requested times.
336 * The incoming signal
339 public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal
) {
340 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
341 final ITmfTrace trace
= entry
.getKey();
342 final TmfTraceContext curCtx
= entry
.getValue();
344 final TmfTimeRange validTr
= getValidTimeRange(trace
);
346 /* Determine the new time range */
347 TmfTimeRange targetTr
= signal
.getCurrentRange().getIntersection(validTr
);
348 TmfTimeRange newTr
= (targetTr
== null ? curCtx
.getWindowRange() : targetTr
);
350 /* Update the values */
351 TmfTraceContext newCtx
= new TmfTraceContext(curCtx
, newTr
);
352 entry
.setValue(newCtx
);
356 // ------------------------------------------------------------------------
357 // Private utility methods
358 // ------------------------------------------------------------------------
361 * Return the valid time range of a trace (not the current window time
362 * range, but the range of all possible valid timestamps).
364 * For a real trace this is the whole range of the trace. For an experiment,
365 * it goes from the start time of the earliest trace to the end time of the
369 * The trace to check for
370 * @return The valid time span, or 'null' if the trace is not valid
372 private TmfTimeRange
getValidTimeRange(ITmfTrace trace
) {
373 if (!fTraces
.containsKey(trace
)) {
374 /* Trace is not part of the currently opened traces */
377 if (!(trace
instanceof TmfExperiment
)) {
378 /* "trace" is a single trace, return its time range directly */
379 return trace
.getTimeRange();
381 final ITmfTrace
[] traces
= ((TmfExperiment
) trace
).getTraces();
382 if (traces
.length
== 0) {
383 /* We are being trolled */
386 if (traces
.length
== 1) {
387 /* Trace is an experiment with only 1 trace */
388 return traces
[0].getTimeRange();
391 * Trace is an experiment with 2+ traces, so get the earliest start and
394 ITmfTimestamp start
= traces
[0].getStartTime();
395 ITmfTimestamp end
= traces
[0].getEndTime();
396 for (int i
= 1; i
< traces
.length
; i
++) {
397 ITmfTrace curTrace
= traces
[i
];
398 if (curTrace
.getStartTime().compareTo(start
) < 0) {
399 start
= curTrace
.getStartTime();
401 if (curTrace
.getEndTime().compareTo(end
) > 0) {
402 end
= curTrace
.getEndTime();
405 return new TmfTimeRange(start
, end
);
409 * Get a temporary directory based on a trace's name. We will create the
410 * directory if it doesn't exist, so that it's ready to be used.
412 private static String
getTemporaryDir(ITmfTrace trace
) {
413 String pathName
= System
.getProperty("java.io.tmpdir") + //$NON-NLS-1$
417 File dir
= new File(pathName
);