tmf: More trace manager unit tests
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfTraceManager.java
1 /*******************************************************************************
2 * Copyright (c) 2013 Ericsson
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
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.core.trace;
14
15 import java.io.File;
16 import java.util.Collections;
17 import java.util.LinkedHashMap;
18 import java.util.Map;
19 import java.util.Set;
20
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;
34
35 /**
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
38 * each one of those.
39 *
40 * It's a singleton class, so only one instance should exist (available via
41 * {@link #getInstance()}).
42 *
43 * @author Alexandre Montplaisir
44 * @since 2.0
45 */
46 public final class TmfTraceManager {
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
52 private final Map<ITmfTrace, TmfTraceContext> fTraces;
53
54 /** The currently-selected trace. Should always be part of the trace map */
55 private ITmfTrace fCurrentTrace = null;
56
57 // ------------------------------------------------------------------------
58 // Constructor
59 // ------------------------------------------------------------------------
60
61 private TmfTraceManager() {
62 fTraces = new LinkedHashMap<ITmfTrace, TmfTraceContext>();
63 TmfSignalManager.registerVIP(this);
64 }
65
66 /** Singleton instance */
67 private static TmfTraceManager tm = null;
68
69 /**
70 * Get an instance of the trace manager.
71 *
72 * @return The trace manager
73 */
74 public static synchronized TmfTraceManager getInstance() {
75 if (tm == null) {
76 tm = new TmfTraceManager();
77 }
78 return tm;
79 }
80
81 // ------------------------------------------------------------------------
82 // Accessors
83 // ------------------------------------------------------------------------
84
85 /**
86 * Return the current selected time.
87 *
88 * @return the current time stamp
89 */
90 public synchronized ITmfTimestamp getCurrentTime() {
91 return getCurrentTraceContext().getTimestamp();
92 }
93
94 /**
95 * Return the current selected range.
96 *
97 * @return the current time range
98 */
99 public synchronized TmfTimeRange getCurrentRange() {
100 return getCurrentTraceContext().getTimerange();
101 }
102
103 /**
104 * Get the currently selected trace (normally, the focused editor).
105 *
106 * @return The active trace
107 */
108 public synchronized ITmfTrace getActiveTrace() {
109 return fCurrentTrace;
110 }
111
112 /**
113 * Get the trace set of the currently active trace.
114 *
115 * @return The active trace set
116 * @see #getTraceSet(ITmfTrace)
117 */
118 public synchronized ITmfTrace[] getActiveTraceSet() {
119 final ITmfTrace trace = fCurrentTrace;
120 return getTraceSet(trace);
121 }
122
123 /**
124 * Get the currently-opened traces, as an unmodifiable set.
125 *
126 * @return A set containing the opened traces
127 */
128 public synchronized Set<ITmfTrace> getOpenedTraces() {
129 return Collections.unmodifiableSet(fTraces.keySet());
130 }
131
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;
137 }
138 return curCtx;
139 }
140
141 // ------------------------------------------------------------------------
142 // Public utility methods
143 // ------------------------------------------------------------------------
144
145 /**
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.
149 *
150 * @param trace
151 * The trace or experiment
152 * @return The corresponding trace set
153 */
154 public static ITmfTrace[] getTraceSet(ITmfTrace trace) {
155 if (trace == null) {
156 return null;
157 }
158 if (trace instanceof TmfExperiment) {
159 TmfExperiment exp = (TmfExperiment) trace;
160 return exp.getTraces();
161 }
162 return new ITmfTrace[] { trace };
163 }
164
165 /**
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
169 * provided.
170 *
171 * @param trace
172 * The trace
173 * @return The path to the supplementary file directory (trailing slash is
174 * INCLUDED!)
175 */
176 public static String getSupplementaryFileDir(ITmfTrace trace) {
177 IResource resource = trace.getResource();
178 if (resource == null) {
179 return getTemporaryDir(trace);
180 }
181
182 String supplDir = null;
183 try {
184 supplDir = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
185 } catch (CoreException e) {
186 return getTemporaryDir(trace);
187 }
188 return supplDir + File.separator;
189 }
190
191 // ------------------------------------------------------------------------
192 // Signal handlers
193 // ------------------------------------------------------------------------
194
195 /**
196 * Signal handler for the traceOpened signal.
197 *
198 * @param signal
199 * The incoming signal
200 */
201 @TmfSignalHandler
202 public synchronized void traceOpened(final TmfTraceOpenedSignal signal) {
203 final ITmfTrace trace = signal.getTrace();
204 final ITmfTimestamp startTs = trace.getStartTime();
205
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));
211
212 final TmfTraceContext startCtx = new TmfTraceContext(startTs, startTr);
213
214 fTraces.put(trace, startCtx);
215
216 /* We also want to set the newly-opened trace as the active trace */
217 fCurrentTrace = trace;
218 }
219
220
221 /**
222 * Handler for the TmfTraceSelectedSignal.
223 *
224 * @param signal
225 * The incoming signal
226 */
227 @TmfSignalHandler
228 public synchronized void traceSelected(final TmfTraceSelectedSignal signal) {
229 final ITmfTrace newTrace = signal.getTrace();
230 if (!fTraces.containsKey(newTrace)) {
231 throw new RuntimeException();
232 }
233 fCurrentTrace = newTrace;
234 }
235
236 /**
237 * Signal handler for the traceClosed signal.
238 *
239 * @param signal
240 * The incoming signal
241 */
242 @TmfSignalHandler
243 public synchronized void traceClosed(final TmfTraceClosedSignal signal) {
244 fTraces.remove(signal.getTrace());
245 if (fTraces.size() == 0) {
246 fCurrentTrace = null;
247 /*
248 * In other cases, we should receive a traceSelected signal that
249 * will indicate which trace is the new one.
250 */
251 }
252 }
253
254 /**
255 * Signal handler for the TmfTimeSynchSignal signal.
256 *
257 * The current time of *all* traces whose range contains the requested new
258 * time will be updated.
259 *
260 * @param signal
261 * The incoming signal
262 */
263 @TmfSignalHandler
264 public synchronized void timeUpdated(final TmfTimeSynchSignal signal) {
265 final ITmfTimestamp ts = signal.getCurrentTime();
266
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);
273 }
274 }
275 }
276
277 /**
278 * Signal handler for the TmfRangeSynchSignal signal.
279 *
280 * The current timestamp and timerange of *all* valid traces will be updated
281 * to the new requested times.
282 *
283 * @param signal
284 * The incoming signal
285 */
286 @TmfSignalHandler
287 public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal) {
288 final ITmfTimestamp signalTs = signal.getCurrentTime();
289
290 for (Map.Entry<ITmfTrace, TmfTraceContext> entry : fTraces.entrySet()) {
291 final ITmfTrace trace = entry.getKey();
292 final TmfTraceContext curCtx = entry.getValue();
293
294 final TmfTimeRange validTr = getValidTimeRange(trace);
295
296 /* Determine the new time stamp */
297 ITmfTimestamp newTs;
298 if (signalTs != null && signalTs.intersects(validTr)) {
299 newTs = signalTs;
300 } else {
301 newTs = curCtx.getTimestamp();
302 }
303
304 /* Determine the new time range */
305 TmfTimeRange targetTr = signal.getCurrentRange().getIntersection(validTr);
306 TmfTimeRange newTr = (targetTr == null ? curCtx.getTimerange() : targetTr);
307
308 /* Update the values */
309 TmfTraceContext newCtx = new TmfTraceContext(newTs, newTr);
310 entry.setValue(newCtx);
311 }
312 }
313
314 // ------------------------------------------------------------------------
315 // Private utility methods
316 // ------------------------------------------------------------------------
317
318 /**
319 * Return the valid time range of a trace (not the "current time range", but
320 * the range of all possible valid timestamps).
321 *
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
324 * latest one.
325 *
326 * @param trace
327 * The trace to check for
328 * @return The valid time span, or 'null' if the trace is not valid
329 */
330 private TmfTimeRange getValidTimeRange(ITmfTrace trace) {
331 if (!fTraces.containsKey(trace)) {
332 /* Trace is not part of the currently opened traces */
333 return null;
334 }
335 if (!(trace instanceof TmfExperiment)) {
336 /* "trace" is a single trace, return its time range directly */
337 return trace.getTimeRange();
338 }
339 final ITmfTrace[] traces = ((TmfExperiment) trace).getTraces();
340 if (traces.length == 0) {
341 /* We are being trolled */
342 return null;
343 }
344 if (traces.length == 1) {
345 /* Trace is an experiment with only 1 trace */
346 return traces[0].getTimeRange();
347 }
348 /*
349 * Trace is an experiment with 2+ traces, so get the earliest start and
350 * the latest end.
351 */
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();
358 }
359 if (curTrace.getEndTime().compareTo(end) > 0) {
360 end = curTrace.getEndTime();
361 }
362 }
363 return new TmfTimeRange(start, end);
364 }
365
366 /**
367 * Get a temporary directory based on a trace's name
368 */
369 private static String getTemporaryDir(ITmfTrace trace) {
370 return System.getProperty("java.io.tmpdir") + //$NON-NLS-1$
371 File.separator +
372 trace.getName() +
373 File.separator;
374 }
375 }
This page took 0.03932 seconds and 5 git commands to generate.