1 /*******************************************************************************
2 * Copyright (c) 2014 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 * Vincent Perot - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.ui
.stream
;
15 import java
.util
.ArrayList
;
16 import java
.util
.HashMap
;
17 import java
.util
.List
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.swt
.SWT
;
22 import org
.eclipse
.swt
.custom
.CTabFolder
;
23 import org
.eclipse
.swt
.custom
.CTabItem
;
24 import org
.eclipse
.swt
.events
.SelectionAdapter
;
25 import org
.eclipse
.swt
.events
.SelectionEvent
;
26 import org
.eclipse
.swt
.widgets
.Composite
;
27 import org
.eclipse
.swt
.widgets
.Display
;
28 import org
.eclipse
.swt
.widgets
.Event
;
29 import org
.eclipse
.swt
.widgets
.Listener
;
30 import org
.eclipse
.swt
.widgets
.Menu
;
31 import org
.eclipse
.swt
.widgets
.MenuItem
;
32 import org
.eclipse
.swt
.widgets
.Table
;
33 import org
.eclipse
.swt
.widgets
.TableColumn
;
34 import org
.eclipse
.swt
.widgets
.TableItem
;
35 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.analysis
.StreamListAnalysis
;
36 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.PcapEvent
;
37 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.TmfPacketStream
;
38 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.TmfPacketStreamBuilder
;
39 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.protocol
.TmfPcapProtocol
;
40 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.signal
.TmfPacketStreamSelectedSignal
;
41 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.trace
.PcapTrace
;
42 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.ui
.Activator
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.ITmfFilterTreeNode
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterAndNode
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterContainsNode
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterNode
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterOrNode
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignal
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
56 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
57 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
58 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterManager
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterView
;
60 import org
.eclipse
.ui
.IViewPart
;
61 import org
.eclipse
.ui
.IWorkbench
;
62 import org
.eclipse
.ui
.IWorkbenchPage
;
63 import org
.eclipse
.ui
.PartInitException
;
64 import org
.eclipse
.ui
.PlatformUI
;
67 * Class that represents the Stream List View. Such a view lists all the
68 * available streams from the current experiment. <br>
70 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
72 * FIXME analysis is leaking ressource. Someone I will not name told me not to worry about it since
73 * AnalysisModule will not be autocloseable later.
75 * @author Vincent Perot
77 public class StreamListView
extends TmfView
{
80 * The Stream List View ID.
82 public static final String ID
= "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
84 private static final String
[] COLUMN_NAMES
=
85 { Messages
.StreamListView_ID
,
86 Messages
.StreamListView_EndpointA
,
87 Messages
.StreamListView_EndpointB
,
88 Messages
.StreamListView_TotalPackets
,
89 Messages
.StreamListView_TotalBytes
,
90 Messages
.StreamListView_PacketsAtoB
,
91 Messages
.StreamListView_BytesAtoB
,
92 Messages
.StreamListView_PacketsBtoA
,
93 Messages
.StreamListView_BytesBtoA
,
94 Messages
.StreamListView_StartTime
,
95 Messages
.StreamListView_StopTime
,
96 Messages
.StreamListView_Duration
,
97 Messages
.StreamListView_BPSAtoB
,
98 Messages
.StreamListView_BPSBtoA
101 private static final int[] COLUMN_SIZES
=
117 private static final String KEY_PROTOCOL
= "$protocol$"; //$NON-NLS-1$
118 private static final String KEY_STREAM
= "$stream$"; //$NON-NLS-1$
120 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
122 private static final long WAIT_TIME
= 1000;
124 private @Nullable CTabFolder fTabFolder
;
125 private @Nullable Map
<TmfPcapProtocol
, Table
> fTableMap
;
127 private @Nullable TmfPacketStream fCurrentStream
;
128 private @Nullable ITmfTrace fCurrentTrace
;
130 private volatile boolean fStopThread
;
133 * Constructor of the StreamListView class.
135 public StreamListView() {
140 * Handler called when an trace is opened.
143 * Contains the information about the selection.
146 public void traceOpened(TmfTraceOpenedSignal signal
) {
147 fCurrentTrace
= signal
.getTrace();
153 * Handler called when an trace is closed. Checks if the trace is the
154 * current trace and update the view accordingly.
157 * Contains the information about the selection.
160 public void traceClosed(TmfTraceClosedSignal signal
) {
161 if (fCurrentTrace
== signal
.getTrace()) {
162 fCurrentTrace
= null;
168 * Handler called when an trace is selected. Checks if the trace has changed
169 * and requests the selected trace if it has not yet been cached.
172 * Contains the information about the selection.
175 public void traceSelected(TmfTraceSelectedSignal signal
) {
176 if (fCurrentTrace
!= signal
.getTrace()) {
177 fCurrentTrace
= signal
.getTrace();
183 private void queryAnalysis() {
184 Thread thread
= new Thread(new Runnable() {
188 ITmfTrace trace
= fCurrentTrace
;
189 if (trace
== null || (!(trace
instanceof PcapTrace
))) {
192 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
193 if (analysis
== null) {
196 while (!analysis
.isFinished() && !fStopThread
) {
199 Thread
.sleep(WAIT_TIME
);
200 } catch (InterruptedException e
) {
201 String message
= e
.getMessage();
202 if (message
== null) {
203 message
= EMPTY_STRING
;
205 Activator
.logError(message
, e
);
209 // Update UI one more time (daft punk)
221 private void resetView() {
223 // Stop thread if needed
226 // Remove all content in tables
227 final Display display
= Display
.getDefault();
228 if (display
== null || display
.isDisposed()) {
231 display
.asyncExec(new Runnable() {
235 if (display
.isDisposed()) {
238 Map
<TmfPcapProtocol
, Table
> tableMap
= fTableMap
;
239 if (tableMap
== null) {
242 for (TmfPcapProtocol protocol
: tableMap
.keySet()) {
243 if (!(tableMap
.get(protocol
).isDisposed())) {
244 tableMap
.get(protocol
).removeAll();
251 private void updateUI() {
252 final Display display
= Display
.getDefault();
253 if (display
== null || display
.isDisposed()) {
256 display
.asyncExec(new Runnable() {
260 if (display
.isDisposed()) {
263 ITmfTrace trace
= fCurrentTrace
;
268 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
269 if (analysis
== null) {
273 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
274 if (tables
== null) {
277 for (TmfPcapProtocol protocol
: tables
.keySet()) {
278 if (protocol
== null) {
279 throw new IllegalStateException();
281 TmfPacketStreamBuilder builder
= analysis
.getBuilder(protocol
);
282 if (builder
!= null && !(tables
.get(protocol
).isDisposed())) {
283 for (TmfPacketStream stream
: builder
.getStreams()) {
286 if (stream
.getID() < tables
.get(protocol
).getItemCount()) {
287 item
= tables
.get(protocol
).getItem(stream
.getID());
289 item
= new TableItem(tables
.get(protocol
), SWT
.NONE
);
291 item
.setText(0, String
.valueOf(stream
.getID()));
292 item
.setText(1, stream
.getFirstEndpoint().toString());
293 item
.setText(2, stream
.getSecondEndpoint().toString());
294 item
.setText(3, String
.valueOf(stream
.getNbPackets()));
295 item
.setText(4, String
.valueOf(stream
.getNbBytes()));
296 item
.setText(5, String
.valueOf(stream
.getNbPacketsAtoB()));
297 item
.setText(6, String
.valueOf(stream
.getNbBytesAtoB()));
298 item
.setText(7, String
.valueOf(stream
.getNbPacketsBtoA()));
299 item
.setText(8, String
.valueOf(stream
.getNbBytesBtoA()));
300 item
.setText(9, stream
.getStartTime().toString());
301 item
.setText(10, stream
.getStopTime().toString());
302 item
.setText(11, String
.format("%.3f", stream
.getDuration())); //$NON-NLS-1$
303 item
.setText(12, String
.format("%.3f", stream
.getBPSAtoB())); //$NON-NLS-1$
304 item
.setText(13, String
.format("%.3f", stream
.getBPSBtoA())); //$NON-NLS-1$
305 item
.setData(KEY_STREAM
, stream
);
315 public void createPartControl(@Nullable Composite parent
) {
317 fTableMap
= new HashMap
<>();
318 fCurrentTrace
= getActiveTrace();
319 fCurrentStream
= null;
322 fTabFolder
= new CTabFolder(parent
, SWT
.NONE
);
323 fTabFolder
.addSelectionListener(new SelectionAdapter() {
326 public void widgetSelected(@Nullable SelectionEvent e
) {
327 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
328 if (tables
== null || e
== null) {
331 TmfPcapProtocol protocol
= (TmfPcapProtocol
) e
.item
.getData(KEY_PROTOCOL
);
332 tables
.get(protocol
).deselectAll();
333 fCurrentStream
= null;
338 // Add items and tables for each protocol
339 for (TmfPcapProtocol protocol
: TmfPcapProtocol
.values()) {
340 if (protocol
.supportsStream()) {
341 CTabItem item
= new CTabItem(fTabFolder
, SWT
.NONE
);
342 item
.setText(protocol
.getName());
343 item
.setData(KEY_PROTOCOL
, protocol
);
344 Table table
= new Table(fTabFolder
, SWT
.NONE
);
345 table
.setHeaderVisible(true);
346 table
.setLinesVisible(true);
348 // Add columns to table
349 for (int i
= 0; i
< COLUMN_NAMES
.length
|| i
< COLUMN_SIZES
.length
; i
++) {
350 TableColumn column
= new TableColumn(table
, SWT
.NONE
);
351 column
.setText(COLUMN_NAMES
[i
]);
352 column
.setWidth(COLUMN_SIZES
[i
]);
354 item
.setControl(table
);
355 table
.addSelectionListener(new SelectionAdapter() {
358 public void widgetSelected(@Nullable SelectionEvent e
) {
362 fCurrentStream
= (TmfPacketStream
) e
.item
.getData(KEY_STREAM
);
367 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
368 if (tables
== null) {
372 tables
.put(protocol
, table
);
374 // Add right click menu
375 Menu menu
= new Menu(table
);
376 MenuItem menuItem
= new MenuItem(menu
, SWT
.PUSH
);
377 menuItem
.setText(Messages
.StreamListView_FollowStream
);
378 menuItem
.addListener(SWT
.Selection
, new Listener() {
381 public void handleEvent(@Nullable Event event
) {
382 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream
);
383 TmfSignalManager
.dispatchSignal(signal
);
386 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
387 menuItem
.setText(Messages
.StreamListView_Clear
);
388 menuItem
.addListener(SWT
.Selection
, new Listener() {
391 public void handleEvent(@Nullable Event event
) {
392 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, null);
393 TmfSignalManager
.dispatchSignal(signal
);
397 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
398 menuItem
.setText(Messages
.StreamListView_ExtractAsFilter
);
399 menuItem
.addListener(SWT
.Selection
, new Listener() {
402 public void handleEvent(@Nullable Event event
) {
404 ITmfFilterTreeNode filter
= generateFilter();
406 // Update view and XML
407 updateFilters(filter
);
411 private void updateFilters(@Nullable ITmfFilterTreeNode filter
) {
412 if (filter
== null) {
417 List
<ITmfFilterTreeNode
> newFilters
= new ArrayList
<>();
418 ITmfFilterTreeNode
[] oldFilters
= FilterManager
.getSavedFilters();
419 for (int i
= 0; i
< oldFilters
.length
; i
++) {
420 newFilters
.add(oldFilters
[i
]);
422 if (!(newFilters
.contains(filter
))) {
423 newFilters
.add(filter
);
424 FilterManager
.setSavedFilters(newFilters
.toArray(new ITmfFilterTreeNode
[newFilters
.size()]));
427 // Update Filter View
429 final IWorkbench wb
= PlatformUI
.getWorkbench();
430 final IWorkbenchPage activePage
= wb
.getActiveWorkbenchWindow().getActivePage();
431 IViewPart view
= activePage
.showView(FilterView
.ID
);
432 FilterView filterView
= (FilterView
) view
;
433 filterView
.addFilter(filter
);
434 } catch (final PartInitException e
) {
435 TraceUtils
.displayErrorMsg(Messages
.StreamListView_ExtractAsFilter
, "Error opening view " + FilterView
.ID
+ e
.getMessage()); //$NON-NLS-1$
436 Activator
.logError("Error opening view " + FilterView
.ID
, e
); //$NON-NLS-1$
442 private @Nullable ITmfFilterTreeNode
generateFilter() {
443 TmfPacketStream stream
= fCurrentStream
;
444 if (stream
== null) {
448 // First stage - root
449 String name
= Messages
.StreamListView_FilterName_Stream
+ ' ' + stream
.getProtocol().getShortName() + ' ' + stream
.getFirstEndpoint()
450 + " <--> " + stream
.getSecondEndpoint(); //$NON-NLS-1$
451 TmfFilterNode root
= new TmfFilterNode(name
);
453 // Second stage - and
454 TmfFilterAndNode and
= new TmfFilterAndNode(root
);
456 // Third stage - protocol + or
457 TmfFilterContainsNode protocolFilter
= new TmfFilterContainsNode(and
);
458 protocolFilter
.setField(stream
.getProtocol().getName());
459 protocolFilter
.setValue(EMPTY_STRING
);
460 TmfFilterOrNode or
= new TmfFilterOrNode(and
);
462 // Fourth stage - and
463 TmfFilterAndNode andA
= new TmfFilterAndNode(or
);
464 TmfFilterAndNode andB
= new TmfFilterAndNode(or
);
466 // Fourth stage - endpoints
467 TmfFilterContainsNode endpointAAndA
= new TmfFilterContainsNode(andA
);
468 endpointAAndA
.setField(PcapEvent
.EVENT_FIELD_PACKET_SOURCE
);
469 endpointAAndA
.setValue(stream
.getFirstEndpoint());
470 TmfFilterContainsNode endpointBAndA
= new TmfFilterContainsNode(andA
);
471 endpointBAndA
.setField(PcapEvent
.EVENT_FIELD_PACKET_DESTINATION
);
472 endpointBAndA
.setValue(stream
.getSecondEndpoint());
473 TmfFilterContainsNode endpointAAndB
= new TmfFilterContainsNode(andB
);
474 endpointAAndB
.setField(PcapEvent
.EVENT_FIELD_PACKET_SOURCE
);
475 endpointAAndB
.setValue(stream
.getSecondEndpoint());
476 TmfFilterContainsNode endpointBAndB
= new TmfFilterContainsNode(andB
);
477 endpointBAndB
.setField(PcapEvent
.EVENT_FIELD_PACKET_DESTINATION
);
478 endpointBAndB
.setValue(stream
.getFirstEndpoint());
487 // Ask the analysis for data.
492 public void setFocus() {
493 CTabFolder tabFolder
= fTabFolder
;
494 if (tabFolder
!= null && !(tabFolder
.isDisposed())) {
495 tabFolder
.setFocus();