Commit | Line | Data |
---|---|---|
866e5b51 | 1 | /******************************************************************************* |
60ae41e1 | 2 | * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others |
866e5b51 FC |
3 | * |
4 | * All rights reserved. This program and the accompanying materials are made | |
5 | * 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: Matthew Khouzam - Initial API and implementation | |
10 | * Contributors: Simon Marchi - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
f357bcd4 | 13 | package org.eclipse.tracecompass.ctf.core.trace; |
866e5b51 | 14 | |
5f715709 MK |
15 | import java.util.ArrayList; |
16 | import java.util.Collection; | |
17 | import java.util.Collections; | |
866e5b51 | 18 | import java.util.HashSet; |
5f715709 | 19 | import java.util.List; |
866e5b51 FC |
20 | import java.util.Set; |
21 | ||
5f715709 MK |
22 | import org.eclipse.jdt.annotation.NonNull; |
23 | import org.eclipse.jdt.annotation.Nullable; | |
680f9173 | 24 | import org.eclipse.tracecompass.ctf.core.CTFException; |
f357bcd4 AM |
25 | import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration; |
26 | import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; | |
27 | import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration; | |
28 | import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; | |
29 | import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; | |
30 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException; | |
866e5b51 FC |
31 | |
32 | /** | |
33 | * <b><u>Stream</u></b> | |
34 | * <p> | |
35 | * Represents a stream in a trace. | |
36 | */ | |
d84419e1 | 37 | public class CTFStream { |
866e5b51 FC |
38 | |
39 | // ------------------------------------------------------------------------ | |
40 | // Attributes | |
41 | // ------------------------------------------------------------------------ | |
42 | ||
866e5b51 FC |
43 | /** |
44 | * The numerical ID of the stream | |
45 | */ | |
994e0846 | 46 | private long fId = 0; |
866e5b51 FC |
47 | |
48 | /** | |
49 | * Declarations of the stream-specific structures | |
50 | */ | |
2ab0ccec | 51 | private StructDeclaration fPacketContextDecl = null; |
6c7592e1 | 52 | private IDeclaration fEventHeaderDecl = null; |
2ab0ccec | 53 | private StructDeclaration fEventContextDecl = null; |
866e5b51 FC |
54 | |
55 | /** | |
56 | * The trace to which the stream belongs | |
57 | */ | |
2ab0ccec | 58 | private CTFTrace fTrace = null; |
866e5b51 FC |
59 | |
60 | /** | |
61 | * Maps event ids to events | |
62 | */ | |
5f715709 MK |
63 | private final ArrayList<IEventDeclaration> fEvents = new ArrayList<>(); |
64 | ||
65 | private boolean fEventUnsetId = false; | |
994e0846 | 66 | private boolean fStreamIdSet = false; |
866e5b51 FC |
67 | |
68 | /** | |
69 | * The inputs associated to this stream | |
70 | */ | |
d84419e1 | 71 | private final Set<CTFStreamInput> fInputs = new HashSet<>(); |
866e5b51 FC |
72 | |
73 | // ------------------------------------------------------------------------ | |
74 | // Constructors | |
75 | // ------------------------------------------------------------------------ | |
76 | ||
77 | /** | |
78 | * Constructs a Stream that belongs to a Trace | |
79 | * | |
80 | * @param trace | |
81 | * The trace to which belongs this stream. | |
82 | */ | |
d84419e1 | 83 | public CTFStream(CTFTrace trace) { |
2ab0ccec | 84 | fTrace = trace; |
866e5b51 FC |
85 | } |
86 | ||
87 | // ------------------------------------------------------------------------ | |
88 | // Getters/Setters/Predicates | |
89 | // ------------------------------------------------------------------------ | |
90 | ||
9ac2eb62 MK |
91 | /** |
92 | * Sets the id of a stream | |
6c7592e1 MK |
93 | * |
94 | * @param id | |
95 | * the id of a stream | |
9ac2eb62 | 96 | */ |
866e5b51 | 97 | public void setId(long id) { |
2ab0ccec | 98 | fId = id; |
994e0846 | 99 | fStreamIdSet = true; |
866e5b51 FC |
100 | } |
101 | ||
9ac2eb62 MK |
102 | /** |
103 | * Gets the id of a stream | |
6c7592e1 | 104 | * |
9ac2eb62 | 105 | * @return id the id of a stream |
994e0846 | 106 | * @since 1.0 |
9ac2eb62 | 107 | */ |
994e0846 | 108 | public long getId() { |
2ab0ccec | 109 | return fId; |
866e5b51 FC |
110 | } |
111 | ||
9ac2eb62 MK |
112 | /** |
113 | * Is the id of a stream set | |
be6df2d8 AM |
114 | * |
115 | * @return If the ID is set or not | |
9ac2eb62 MK |
116 | */ |
117 | public boolean isIdSet() { | |
994e0846 | 118 | return fStreamIdSet; |
866e5b51 FC |
119 | } |
120 | ||
9ac2eb62 MK |
121 | /** |
122 | * | |
123 | * @return is the event header set (timestamp and stuff) (see Ctf Spec) | |
124 | */ | |
125 | public boolean isEventHeaderSet() { | |
2ab0ccec | 126 | return fEventHeaderDecl != null; |
866e5b51 FC |
127 | } |
128 | ||
9ac2eb62 | 129 | /** |
6c7592e1 MK |
130 | * |
131 | * @return is the event context set (pid and stuff) (see Ctf Spec) | |
132 | */ | |
9ac2eb62 | 133 | public boolean isEventContextSet() { |
2ab0ccec | 134 | return fEventContextDecl != null; |
866e5b51 FC |
135 | } |
136 | ||
9ac2eb62 MK |
137 | /** |
138 | * | |
139 | * @return Is the packet context set (see Ctf Spec) | |
140 | */ | |
141 | public boolean isPacketContextSet() { | |
2ab0ccec | 142 | return fPacketContextDecl != null; |
866e5b51 FC |
143 | } |
144 | ||
9ac2eb62 | 145 | /** |
6c7592e1 | 146 | * Sets the event header |
9ac2eb62 | 147 | * |
6c7592e1 MK |
148 | * @param eventHeader |
149 | * the current event header for all events in this stream | |
9ac2eb62 | 150 | */ |
866e5b51 | 151 | public void setEventHeader(StructDeclaration eventHeader) { |
2ab0ccec | 152 | fEventHeaderDecl = eventHeader; |
866e5b51 FC |
153 | } |
154 | ||
9ac2eb62 | 155 | /** |
6c7592e1 | 156 | * Sets the event header, this typically has the id and the timestamp |
9ac2eb62 | 157 | * |
6c7592e1 MK |
158 | * @param eventHeader |
159 | * the current event header for all events in this stream | |
6c7592e1 MK |
160 | */ |
161 | public void setEventHeader(IEventHeaderDeclaration eventHeader) { | |
162 | fEventHeaderDecl = eventHeader; | |
163 | } | |
164 | ||
165 | /** | |
166 | * | |
167 | * @param eventContext | |
168 | * the context for all events in this stream | |
9ac2eb62 | 169 | */ |
866e5b51 | 170 | public void setEventContext(StructDeclaration eventContext) { |
2ab0ccec | 171 | fEventContextDecl = eventContext; |
866e5b51 FC |
172 | } |
173 | ||
9ac2eb62 MK |
174 | /** |
175 | * | |
6c7592e1 MK |
176 | * @param packetContext |
177 | * the packet context for all packets in this stream | |
9ac2eb62 | 178 | */ |
866e5b51 | 179 | public void setPacketContext(StructDeclaration packetContext) { |
2ab0ccec | 180 | fPacketContextDecl = packetContext; |
866e5b51 FC |
181 | } |
182 | ||
6c7592e1 MK |
183 | /** |
184 | * Gets the event header declaration | |
185 | * | |
186 | * @return the event header declaration in declaration form | |
6c7592e1 MK |
187 | */ |
188 | public IDeclaration getEventHeaderDeclaration() { | |
2ab0ccec | 189 | return fEventHeaderDecl; |
866e5b51 FC |
190 | } |
191 | ||
9ac2eb62 MK |
192 | /** |
193 | * | |
194 | * @return the event context declaration in structdeclaration form | |
195 | */ | |
866e5b51 | 196 | public StructDeclaration getEventContextDecl() { |
2ab0ccec | 197 | return fEventContextDecl; |
866e5b51 FC |
198 | } |
199 | ||
9ac2eb62 MK |
200 | /** |
201 | * | |
202 | * @return the packet context declaration in structdeclaration form | |
203 | */ | |
866e5b51 | 204 | public StructDeclaration getPacketContextDecl() { |
2ab0ccec | 205 | return fPacketContextDecl; |
866e5b51 FC |
206 | } |
207 | ||
9ac2eb62 MK |
208 | /** |
209 | * | |
210 | * @return the set of all stream inputs for this stream | |
211 | */ | |
d84419e1 | 212 | public Set<CTFStreamInput> getStreamInputs() { |
2ab0ccec | 213 | return fInputs; |
866e5b51 FC |
214 | } |
215 | ||
9ac2eb62 MK |
216 | /** |
217 | * | |
218 | * @return the parent trace | |
219 | */ | |
866e5b51 | 220 | public CTFTrace getTrace() { |
2ab0ccec | 221 | return fTrace; |
866e5b51 FC |
222 | } |
223 | ||
5f715709 MK |
224 | /** |
225 | * Get all the event declarations in this stream. | |
226 | * | |
227 | * @return The event declarations for this stream | |
5f715709 MK |
228 | */ |
229 | public @NonNull Collection<IEventDeclaration> getEventDeclarations() { | |
230 | List<IEventDeclaration> retVal = new ArrayList<>(fEvents); | |
231 | retVal.removeAll(Collections.<IEventDeclaration> singletonList(null)); | |
232 | return retVal; | |
233 | } | |
234 | ||
235 | /** | |
236 | * Get the event declaration for a given ID. | |
237 | * | |
238 | * @param eventId | |
239 | * The ID, can be {@link EventDeclaration#UNSET_EVENT_ID}, or any | |
240 | * positive value | |
241 | * @return The event declaration with the given ID for this stream, or | |
242 | * 'null' if there are no declaration with this ID | |
243 | * @throws IllegalArgumentException | |
244 | * If the passed ID is invalid | |
5f715709 MK |
245 | */ |
246 | public @Nullable IEventDeclaration getEventDeclaration(int eventId) { | |
a433ce7d | 247 | int eventIndex = (eventId == IEventDeclaration.UNSET_EVENT_ID) ? 0 : eventId; |
5f715709 MK |
248 | if (eventIndex < 0) { |
249 | /* Any negative value other than UNSET_EVENT_ID is invalid */ | |
250 | throw new IllegalArgumentException("Event ID cannot be negative."); //$NON-NLS-1$ | |
251 | } | |
252 | if (eventIndex >= fEvents.size()) { | |
253 | /* This ID could be valid, but there are no declarations with it */ | |
254 | return null; | |
255 | } | |
256 | return fEvents.get(eventIndex); | |
866e5b51 FC |
257 | } |
258 | ||
259 | // ------------------------------------------------------------------------ | |
260 | // Operations | |
261 | // ------------------------------------------------------------------------ | |
262 | ||
263 | /** | |
5f715709 | 264 | * Adds an event to the event list. |
866e5b51 FC |
265 | * |
266 | * An event in a stream can omit its id if it is the only event in this | |
267 | * stream. An event for which no id has been specified has a null id. It is | |
268 | * thus not possible to add an event with the null key if the map is not | |
269 | * empty. It is also not possible to add an event to the map if the null key | |
270 | * is present in the map. | |
271 | * | |
272 | * @param event | |
be6df2d8 | 273 | * The event to add |
866e5b51 | 274 | * @throws ParseException |
be6df2d8 AM |
275 | * If there was a problem reading the event or adding it to the |
276 | * stream | |
866e5b51 | 277 | */ |
8e964be1 | 278 | public void addEvent(IEventDeclaration event) throws ParseException { |
5f715709 | 279 | if (fEventUnsetId) { |
6c7592e1 | 280 | throw new ParseException("Event without id with multiple events in a stream"); //$NON-NLS-1$ |
866e5b51 | 281 | } |
5f715709 | 282 | int id = ((EventDeclaration) event).id(); |
866e5b51 FC |
283 | |
284 | /* | |
285 | * If there is an event without id (the null key), it must be the only | |
286 | * one | |
287 | */ | |
a433ce7d | 288 | if (id == IEventDeclaration.UNSET_EVENT_ID) { |
5f715709 MK |
289 | if (!fEvents.isEmpty()) { |
290 | throw new ParseException("Event without id with multiple events in a stream"); //$NON-NLS-1$ | |
291 | } | |
292 | fEventUnsetId = true; | |
293 | fEvents.add(event); | |
294 | } else { | |
295 | /* Check if an event with the same ID already exists */ | |
296 | if (fEvents.size() > id && fEvents.get(id) != null) { | |
297 | throw new ParseException("Event id already exists"); //$NON-NLS-1$ | |
298 | } | |
299 | ensureSize(fEvents, id); | |
300 | /* Put the event in the list */ | |
301 | fEvents.set(id, event); | |
866e5b51 | 302 | } |
5f715709 | 303 | } |
866e5b51 | 304 | |
5f715709 MK |
305 | /** |
306 | * Add a list of event declarations to this stream. There must be no overlap | |
307 | * between the two lists of event declarations. This will merge the two | |
308 | * lists and preserve the indexes of both lists. | |
309 | * | |
310 | * @param events | |
311 | * list of the events to add | |
680f9173 | 312 | * @throws CTFException |
5f715709 | 313 | * if the list already contains data |
5f715709 | 314 | */ |
680f9173 | 315 | public void addEvents(Collection<IEventDeclaration> events) throws CTFException { |
5f715709 | 316 | if (fEventUnsetId) { |
680f9173 | 317 | throw new CTFException("Cannot add to a stream with an unidentified event"); //$NON-NLS-1$ |
866e5b51 | 318 | } |
5f715709 MK |
319 | if (fEvents.isEmpty()) { |
320 | fEvents.addAll(events); | |
321 | return; | |
322 | } | |
323 | for (IEventDeclaration event : events) { | |
324 | if (event != null) { | |
325 | int index = event.getId().intValue(); | |
326 | ensureSize(fEvents, index); | |
327 | if (fEvents.get(index) != null) { | |
680f9173 | 328 | throw new CTFException("Both lists have an event defined at position " + index); //$NON-NLS-1$ |
5f715709 MK |
329 | } |
330 | fEvents.set(index, event); | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
335 | private static void ensureSize(ArrayList<? extends Object> list, int index) { | |
336 | list.ensureCapacity(index); | |
337 | while (list.size() <= index) { | |
338 | list.add(null); | |
b73145e2 | 339 | } |
866e5b51 FC |
340 | } |
341 | ||
342 | /** | |
343 | * Add an input to this Stream | |
344 | * | |
345 | * @param input | |
346 | * The StreamInput to add. | |
347 | */ | |
d84419e1 | 348 | public void addInput(CTFStreamInput input) { |
2ab0ccec | 349 | fInputs.add(input); |
866e5b51 FC |
350 | } |
351 | ||
866e5b51 FC |
352 | @Override |
353 | public String toString() { | |
2ab0ccec MK |
354 | return "Stream [id=" + fId + ", packetContextDecl=" + fPacketContextDecl //$NON-NLS-1$ //$NON-NLS-2$ |
355 | + ", eventHeaderDecl=" + fEventHeaderDecl //$NON-NLS-1$ | |
356 | + ", eventContextDecl=" + fEventContextDecl + ", trace=" + fTrace //$NON-NLS-1$ //$NON-NLS-2$ | |
357 | + ", events=" + fEvents + ", inputs=" + fInputs + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
866e5b51 FC |
358 | } |
359 | } |