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