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