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 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
16 import java
.util
.Collections
;
17 import java
.util
.LinkedHashMap
;
21 import org
.eclipse
.core
.resources
.IResource
;
22 import org
.eclipse
.core
.runtime
.CoreException
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
36 * Central trace manager for TMF. It tracks the currently opened traces and
37 * experiment, as well as the currently-selected timestamps and time ranges for
40 * It's a singleton class, so only one instance should exist (available via
41 * {@link #getInstance()}).
43 * @author Alexandre Montplaisir
46 public final class TmfTraceManager
{
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
52 private final Map
<ITmfTrace
, TmfTraceContext
> fTraces
;
54 /** The currently-selected trace. Should always be part of the trace map */
55 private ITmfTrace fCurrentTrace
= null;
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
61 private TmfTraceManager() {
62 fTraces
= new LinkedHashMap
<ITmfTrace
, TmfTraceContext
>();
63 TmfSignalManager
.registerVIP(this);
66 /** Singleton instance */
67 private static TmfTraceManager tm
= null;
70 * Get an instance of the trace manager.
72 * @return The trace manager
74 public static synchronized TmfTraceManager
getInstance() {
76 tm
= new TmfTraceManager();
81 // ------------------------------------------------------------------------
83 // ------------------------------------------------------------------------
86 * Return the current selected time.
88 * @return the current time stamp
90 public synchronized ITmfTimestamp
getCurrentTime() {
91 return getCurrentTraceContext().getTimestamp();
95 * Return the current selected range.
97 * @return the current time range
99 public synchronized TmfTimeRange
getCurrentRange() {
100 return getCurrentTraceContext().getTimerange();
104 * Get the currently selected trace (normally, the focused editor).
106 * @return The active trace
108 public synchronized ITmfTrace
getActiveTrace() {
109 return fCurrentTrace
;
113 * Get the trace set of the currently active trace.
115 * @return The active trace set
116 * @see #getTraceSet(ITmfTrace)
118 public synchronized ITmfTrace
[] getActiveTraceSet() {
119 final ITmfTrace trace
= fCurrentTrace
;
120 return getTraceSet(trace
);
124 * Get the currently-opened traces, as an unmodifiable set.
126 * @return A set containing the opened traces
128 public synchronized Set
<ITmfTrace
> getOpenedTraces() {
129 return Collections
.unmodifiableSet(fTraces
.keySet());
132 private TmfTraceContext
getCurrentTraceContext() {
133 TmfTraceContext curCtx
= fTraces
.get(fCurrentTrace
);
134 if (curCtx
== null) {
135 /* There are no traces opened at the moment. */
136 return TmfTraceContext
.NULL_CONTEXT
;
141 // ------------------------------------------------------------------------
142 // Public utility methods
143 // ------------------------------------------------------------------------
146 * Get the trace set of a given trace. For a standard trace, this is simply
147 * an array with only that trace in it. For experiments, this is an array of
148 * all the traces contained in this experiment.
151 * The trace or experiment
152 * @return The corresponding trace set
154 public static ITmfTrace
[] getTraceSet(ITmfTrace trace
) {
158 if (trace
instanceof TmfExperiment
) {
159 TmfExperiment exp
= (TmfExperiment
) trace
;
160 return exp
.getTraces();
162 return new ITmfTrace
[] { trace
};
166 * Return the path (as a string) to the directory for supplementary files to
167 * use with a given trace. If no supplementary file directory has been
168 * configured, a temporary directory based on the trace's name will be
173 * @return The path to the supplementary file directory (trailing slash is
176 public static String
getSupplementaryFileDir(ITmfTrace trace
) {
177 IResource resource
= trace
.getResource();
178 if (resource
== null) {
179 return getTemporaryDir(trace
);
182 String supplDir
= null;
184 supplDir
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
185 } catch (CoreException e
) {
186 return getTemporaryDir(trace
);
188 return supplDir
+ File
.separator
;
191 // ------------------------------------------------------------------------
193 // ------------------------------------------------------------------------
196 * Signal handler for the traceOpened signal.
199 * The incoming signal
202 public synchronized void traceOpened(final TmfTraceOpenedSignal signal
) {
203 final ITmfTrace trace
= signal
.getTrace();
204 final ITmfTimestamp startTs
= trace
.getStartTime();
206 /* Calculate the initial time range */
207 final int SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
208 long offset
= trace
.getInitialRangeOffset().normalize(0, SCALE
).getValue();
209 long endTime
= startTs
.normalize(0, SCALE
).getValue() + offset
;
210 final TmfTimeRange startTr
= new TmfTimeRange(startTs
, new TmfTimestamp(endTime
, SCALE
));
212 final TmfTraceContext startCtx
= new TmfTraceContext(startTs
, startTr
);
214 fTraces
.put(trace
, startCtx
);
216 /* We also want to set the newly-opened trace as the active trace */
217 fCurrentTrace
= trace
;
222 * Handler for the TmfTraceSelectedSignal.
225 * The incoming signal
228 public synchronized void traceSelected(final TmfTraceSelectedSignal signal
) {
229 final ITmfTrace newTrace
= signal
.getTrace();
230 if (!fTraces
.containsKey(newTrace
)) {
231 throw new RuntimeException();
233 fCurrentTrace
= newTrace
;
237 * Signal handler for the traceClosed signal.
240 * The incoming signal
243 public synchronized void traceClosed(final TmfTraceClosedSignal signal
) {
244 fTraces
.remove(signal
.getTrace());
245 if (fTraces
.size() == 0) {
246 fCurrentTrace
= null;
248 * In other cases, we should receive a traceSelected signal that
249 * will indicate which trace is the new one.
255 * Signal handler for the TmfTimeSynchSignal signal.
257 * The current time of *all* traces whose range contains the requested new
258 * time will be updated.
261 * The incoming signal
264 public synchronized void timeUpdated(final TmfTimeSynchSignal signal
) {
265 final ITmfTimestamp ts
= signal
.getCurrentTime();
267 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
268 final ITmfTrace trace
= entry
.getKey();
269 if (ts
.intersects(getValidTimeRange(trace
))) {
270 TmfTraceContext prevCtx
= entry
.getValue();
271 TmfTraceContext newCtx
= new TmfTraceContext(prevCtx
, ts
);
272 entry
.setValue(newCtx
);
278 * Signal handler for the TmfRangeSynchSignal signal.
280 * The current timestamp and timerange of *all* valid traces will be updated
281 * to the new requested times.
284 * The incoming signal
287 public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal
) {
288 final ITmfTimestamp signalTs
= signal
.getCurrentTime();
290 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
291 final ITmfTrace trace
= entry
.getKey();
292 final TmfTraceContext curCtx
= entry
.getValue();
294 final TmfTimeRange validTr
= getValidTimeRange(trace
);
296 /* Determine the new time stamp */
298 if (signalTs
!= null && signalTs
.intersects(validTr
)) {
301 newTs
= curCtx
.getTimestamp();
304 /* Determine the new time range */
305 TmfTimeRange targetTr
= signal
.getCurrentRange().getIntersection(validTr
);
306 TmfTimeRange newTr
= (targetTr
== null ? curCtx
.getTimerange() : targetTr
);
308 /* Update the values */
309 TmfTraceContext newCtx
= new TmfTraceContext(newTs
, newTr
);
310 entry
.setValue(newCtx
);
314 // ------------------------------------------------------------------------
315 // Private utility methods
316 // ------------------------------------------------------------------------
319 * Return the valid time range of a trace (not the "current time range", but
320 * the range of all possible valid timestamps).
322 * For a real trace this is the whole range of the trace. For an experiment,
323 * it goes from the start time of the earliest trace to the end time of the
327 * The trace to check for
328 * @return The valid time span, or 'null' if the trace is not valid
330 private TmfTimeRange
getValidTimeRange(ITmfTrace trace
) {
331 if (!fTraces
.containsKey(trace
)) {
332 /* Trace is not part of the currently opened traces */
335 if (!(trace
instanceof TmfExperiment
)) {
336 /* "trace" is a single trace, return its time range directly */
337 return trace
.getTimeRange();
339 final ITmfTrace
[] traces
= ((TmfExperiment
) trace
).getTraces();
340 if (traces
.length
== 0) {
341 /* We are being trolled */
344 if (traces
.length
== 1) {
345 /* Trace is an experiment with only 1 trace */
346 return traces
[0].getTimeRange();
349 * Trace is an experiment with 2+ traces, so get the earliest start and
352 ITmfTimestamp start
= traces
[0].getStartTime();
353 ITmfTimestamp end
= traces
[0].getEndTime();
354 for (int i
= 1; i
< traces
.length
; i
++) {
355 ITmfTrace curTrace
= traces
[i
];
356 if (curTrace
.getStartTime().compareTo(start
) < 0) {
357 start
= curTrace
.getStartTime();
359 if (curTrace
.getEndTime().compareTo(end
) > 0) {
360 end
= curTrace
.getEndTime();
363 return new TmfTimeRange(start
, end
);
367 * Get a temporary directory based on a trace's name
369 private static String
getTemporaryDir(ITmfTrace trace
) {
370 return System
.getProperty("java.io.tmpdir") + //$NON-NLS-1$