1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 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 * Patrick Tasse - Support aspect filters
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.ui
.stream
;
16 import java
.util
.HashMap
;
17 import java
.util
.List
;
19 import java
.util
.Map
.Entry
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.swt
.SWT
;
23 import org
.eclipse
.swt
.custom
.CTabFolder
;
24 import org
.eclipse
.swt
.custom
.CTabItem
;
25 import org
.eclipse
.swt
.events
.SelectionAdapter
;
26 import org
.eclipse
.swt
.events
.SelectionEvent
;
27 import org
.eclipse
.swt
.widgets
.Composite
;
28 import org
.eclipse
.swt
.widgets
.Display
;
29 import org
.eclipse
.swt
.widgets
.Event
;
30 import org
.eclipse
.swt
.widgets
.Listener
;
31 import org
.eclipse
.swt
.widgets
.Menu
;
32 import org
.eclipse
.swt
.widgets
.MenuItem
;
33 import org
.eclipse
.swt
.widgets
.Table
;
34 import org
.eclipse
.swt
.widgets
.TableColumn
;
35 import org
.eclipse
.swt
.widgets
.TableItem
;
36 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.analysis
.StreamListAnalysis
;
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
.event
.aspect
.PcapDestinationAspect
;
40 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.aspect
.PcapSourceAspect
;
41 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.protocol
.TmfPcapProtocol
;
42 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.signal
.TmfPacketStreamSelectedSignal
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.trace
.PcapTrace
;
44 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.ui
.Activator
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.event
.aspect
.TmfBaseAspects
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.ITmfFilterTreeNode
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterAndNode
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterAspectNode
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterContainsNode
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterNode
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterOrNode
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignal
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
59 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
60 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
61 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
62 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
63 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterManager
;
64 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterView
;
65 import org
.eclipse
.ui
.IViewPart
;
66 import org
.eclipse
.ui
.IWorkbench
;
67 import org
.eclipse
.ui
.IWorkbenchPage
;
68 import org
.eclipse
.ui
.PartInitException
;
69 import org
.eclipse
.ui
.PlatformUI
;
71 import com
.google
.common
.collect
.Lists
;
74 * Class that represents the Stream List View. Such a view lists all the
75 * available streams from the current experiment. <br>
77 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
79 * FIXME analysis is leaking ressource. Someone I will not name told me not to worry about it since
80 * AnalysisModule will not be autocloseable later.
82 * @author Vincent Perot
84 public class StreamListView
extends TmfView
{
87 * The Stream List View ID.
89 public static final String ID
= "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
91 private static final String
[] COLUMN_NAMES
=
92 { Messages
.StreamListView_ID
,
93 Messages
.StreamListView_EndpointA
,
94 Messages
.StreamListView_EndpointB
,
95 Messages
.StreamListView_TotalPackets
,
96 Messages
.StreamListView_TotalBytes
,
97 Messages
.StreamListView_PacketsAtoB
,
98 Messages
.StreamListView_BytesAtoB
,
99 Messages
.StreamListView_PacketsBtoA
,
100 Messages
.StreamListView_BytesBtoA
,
101 Messages
.StreamListView_StartTime
,
102 Messages
.StreamListView_StopTime
,
103 Messages
.StreamListView_Duration
,
104 Messages
.StreamListView_BPSAtoB
,
105 Messages
.StreamListView_BPSBtoA
108 private static final int[] COLUMN_SIZES
=
124 private static final String KEY_PROTOCOL
= "$protocol$"; //$NON-NLS-1$
125 private static final String KEY_STREAM
= "$stream$"; //$NON-NLS-1$
127 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
129 private static final long WAIT_TIME
= 1000;
131 private @Nullable CTabFolder fTabFolder
;
132 private @Nullable Map
<TmfPcapProtocol
, Table
> fTableMap
;
134 private @Nullable TmfPacketStream fCurrentStream
;
135 private @Nullable ITmfTrace fCurrentTrace
;
137 private volatile boolean fStopThread
;
140 * Constructor of the StreamListView class.
142 public StreamListView() {
147 * Handler called when an trace is opened.
150 * Contains the information about the selection.
153 public void traceOpened(TmfTraceOpenedSignal signal
) {
154 fCurrentTrace
= signal
.getTrace();
160 * Handler called when an trace is closed. Checks if the trace is the
161 * current trace and update the view accordingly.
164 * Contains the information about the selection.
167 public void traceClosed(TmfTraceClosedSignal signal
) {
168 if (fCurrentTrace
== signal
.getTrace()) {
169 fCurrentTrace
= null;
175 * Handler called when an trace is selected. Checks if the trace has changed
176 * and requests the selected trace if it has not yet been cached.
179 * Contains the information about the selection.
182 public void traceSelected(TmfTraceSelectedSignal signal
) {
183 if (fCurrentTrace
!= signal
.getTrace()) {
184 fCurrentTrace
= signal
.getTrace();
190 private void queryAnalysis() {
191 Thread thread
= new Thread(new Runnable() {
195 ITmfTrace trace
= fCurrentTrace
;
196 if (trace
== null || (!(trace
instanceof PcapTrace
))) {
199 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
200 if (analysis
== null) {
203 while (!analysis
.isFinished() && !fStopThread
) {
206 Thread
.sleep(WAIT_TIME
);
207 } catch (InterruptedException e
) {
208 String message
= e
.getMessage();
209 if (message
== null) {
210 message
= EMPTY_STRING
;
212 Activator
.logError(message
, e
);
216 // Update UI one more time (daft punk)
228 private void resetView() {
230 // Stop thread if needed
233 // Remove all content in tables
234 final Display display
= Display
.getDefault();
235 if (display
== null || display
.isDisposed()) {
238 display
.asyncExec(new Runnable() {
242 if (display
.isDisposed()) {
245 Map
<TmfPcapProtocol
, Table
> tableMap
= fTableMap
;
246 if (tableMap
== null) {
249 for (Table table
: tableMap
.values()) {
250 if (!table
.isDisposed()) {
258 private void updateUI() {
259 final Display display
= Display
.getDefault();
260 if (display
== null || display
.isDisposed()) {
263 display
.asyncExec(new Runnable() {
267 if (display
.isDisposed()) {
270 ITmfTrace trace
= fCurrentTrace
;
275 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
276 if (analysis
== null) {
280 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
281 if (tables
== null) {
284 for (Entry
<TmfPcapProtocol
, Table
> protocolEntry
: tables
.entrySet()) {
285 TmfPcapProtocol protocol
= protocolEntry
.getKey();
286 TmfPacketStreamBuilder builder
= analysis
.getBuilder(protocol
);
287 Table table
= protocolEntry
.getValue();
288 if (builder
!= null && !(table
.isDisposed())) {
289 for (TmfPacketStream stream
: builder
.getStreams()) {
292 if (stream
.getID() < table
.getItemCount()) {
293 item
= table
.getItem(stream
.getID());
295 item
= new TableItem(table
, SWT
.NONE
);
297 item
.setText(0, String
.valueOf(stream
.getID()));
298 item
.setText(1, stream
.getFirstEndpoint().toString());
299 item
.setText(2, stream
.getSecondEndpoint().toString());
300 item
.setText(3, String
.valueOf(stream
.getNbPackets()));
301 item
.setText(4, String
.valueOf(stream
.getNbBytes()));
302 item
.setText(5, String
.valueOf(stream
.getNbPacketsAtoB()));
303 item
.setText(6, String
.valueOf(stream
.getNbBytesAtoB()));
304 item
.setText(7, String
.valueOf(stream
.getNbPacketsBtoA()));
305 item
.setText(8, String
.valueOf(stream
.getNbBytesBtoA()));
306 item
.setText(9, stream
.getStartTime().toString());
307 item
.setText(10, stream
.getStopTime().toString());
308 item
.setText(11, String
.format("%.3f", stream
.getDuration())); //$NON-NLS-1$
309 item
.setText(12, String
.format("%.3f", stream
.getBPSAtoB())); //$NON-NLS-1$
310 item
.setText(13, String
.format("%.3f", stream
.getBPSBtoA())); //$NON-NLS-1$
311 item
.setData(KEY_STREAM
, stream
);
321 public void createPartControl(@Nullable Composite parent
) {
323 final Map
<TmfPcapProtocol
, Table
> tables
= new HashMap
<>();
325 fCurrentTrace
= TmfTraceManager
.getInstance().getActiveTrace();
326 fCurrentStream
= null;
329 fTabFolder
= new CTabFolder(parent
, SWT
.NONE
);
330 fTabFolder
.addSelectionListener(new SelectionAdapter() {
333 public void widgetSelected(@Nullable SelectionEvent e
) {
337 TmfPcapProtocol protocol
= (TmfPcapProtocol
) e
.item
.getData(KEY_PROTOCOL
);
338 final Table table
= tables
.get(protocol
);
342 fCurrentStream
= null;
347 // Add items and tables for each protocol
348 for (TmfPcapProtocol protocol
: TmfPcapProtocol
.values()) {
349 if (protocol
.supportsStream()) {
350 CTabItem item
= new CTabItem(fTabFolder
, SWT
.NONE
);
351 item
.setText(protocol
.getName());
352 item
.setData(KEY_PROTOCOL
, protocol
);
353 Table table
= new Table(fTabFolder
, SWT
.NONE
);
354 table
.setHeaderVisible(true);
355 table
.setLinesVisible(true);
357 // Add columns to table
358 for (int i
= 0; i
< COLUMN_NAMES
.length
|| i
< COLUMN_SIZES
.length
; i
++) {
359 TableColumn column
= new TableColumn(table
, SWT
.NONE
);
360 column
.setText(COLUMN_NAMES
[i
]);
361 column
.setWidth(COLUMN_SIZES
[i
]);
363 item
.setControl(table
);
364 table
.addSelectionListener(new SelectionAdapter() {
367 public void widgetSelected(@Nullable SelectionEvent e
) {
371 fCurrentStream
= (TmfPacketStream
) e
.item
.getData(KEY_STREAM
);
376 tables
.put(protocol
, table
);
378 // Add right click menu
379 Menu menu
= new Menu(table
);
380 MenuItem menuItem
= new MenuItem(menu
, SWT
.PUSH
);
381 menuItem
.setText(Messages
.StreamListView_FollowStream
);
382 menuItem
.addListener(SWT
.Selection
, new Listener() {
385 public void handleEvent(@Nullable Event event
) {
386 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream
);
387 TmfSignalManager
.dispatchSignal(signal
);
390 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
391 menuItem
.setText(Messages
.StreamListView_Clear
);
392 menuItem
.addListener(SWT
.Selection
, new Listener() {
395 public void handleEvent(@Nullable Event event
) {
396 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, null);
397 TmfSignalManager
.dispatchSignal(signal
);
401 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
402 menuItem
.setText(Messages
.StreamListView_ExtractAsFilter
);
403 menuItem
.addListener(SWT
.Selection
, new Listener() {
406 public void handleEvent(@Nullable Event event
) {
408 ITmfFilterTreeNode filter
= generateFilter();
410 // Update view and XML
411 updateFilters(filter
);
415 private void updateFilters(@Nullable ITmfFilterTreeNode filter
) {
416 if (filter
== null) {
421 List
<ITmfFilterTreeNode
> filters
= Lists
.newArrayList(FilterManager
.getSavedFilters());
422 boolean newFilter
= true;
423 for (ITmfFilterTreeNode savedFilter
: filters
) {
424 // Use toString(explicit) equality because equals() is not implemented
425 if (savedFilter
.toString(true).equals(filter
.toString(true))) {
432 FilterManager
.setSavedFilters(filters
.toArray(new ITmfFilterTreeNode
[filters
.size()]));
435 // Update Filter View
437 final IWorkbench wb
= PlatformUI
.getWorkbench();
438 final IWorkbenchPage activePage
= wb
.getActiveWorkbenchWindow().getActivePage();
439 IViewPart view
= activePage
.showView(FilterView
.ID
);
440 FilterView filterView
= (FilterView
) view
;
441 filterView
.addFilter(filter
);
442 } catch (final PartInitException e
) {
443 TraceUtils
.displayErrorMsg(Messages
.StreamListView_ExtractAsFilter
, "Error opening view " + FilterView
.ID
+ e
.getMessage()); //$NON-NLS-1$
444 Activator
.logError("Error opening view " + FilterView
.ID
, e
); //$NON-NLS-1$
450 private @Nullable ITmfFilterTreeNode
generateFilter() {
451 TmfPacketStream stream
= fCurrentStream
;
452 if (stream
== null) {
456 // First stage - root
457 String name
= Messages
.StreamListView_FilterName_Stream
+ ' ' + stream
.getProtocol().getShortName() + ' ' + stream
.getFirstEndpoint()
458 + " <--> " + stream
.getSecondEndpoint(); //$NON-NLS-1$
459 TmfFilterNode root
= new TmfFilterNode(name
);
461 // Second stage - and
462 TmfFilterAndNode and
= new TmfFilterAndNode(root
);
464 // Third stage - protocol + or
465 TmfFilterContainsNode protocolFilter
= new TmfFilterContainsNode(and
);
466 protocolFilter
.setEventAspect(TmfBaseAspects
.getContentsAspect().forField(stream
.getProtocol().getName()));
467 protocolFilter
.setTraceTypeId(TmfFilterAspectNode
.BASE_ASPECT_ID
);
468 protocolFilter
.setValue(EMPTY_STRING
);
469 TmfFilterOrNode or
= new TmfFilterOrNode(and
);
471 // Fourth stage - and
472 TmfFilterAndNode andA
= new TmfFilterAndNode(or
);
473 TmfFilterAndNode andB
= new TmfFilterAndNode(or
);
475 // Fourth stage - endpoints
476 TmfFilterContainsNode endpointAAndA
= new TmfFilterContainsNode(andA
);
477 endpointAAndA
.setEventAspect(PcapSourceAspect
.INSTANCE
);
478 endpointAAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
479 endpointAAndA
.setValue(stream
.getFirstEndpoint());
480 TmfFilterContainsNode endpointBAndA
= new TmfFilterContainsNode(andA
);
481 endpointBAndA
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
482 endpointBAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
483 endpointBAndA
.setValue(stream
.getSecondEndpoint());
484 TmfFilterContainsNode endpointAAndB
= new TmfFilterContainsNode(andB
);
485 endpointAAndB
.setEventAspect(PcapSourceAspect
.INSTANCE
);
486 endpointAAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
487 endpointAAndB
.setValue(stream
.getSecondEndpoint());
488 TmfFilterContainsNode endpointBAndB
= new TmfFilterContainsNode(andB
);
489 endpointBAndB
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
490 endpointBAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
491 endpointBAndB
.setValue(stream
.getFirstEndpoint());
500 // Ask the analysis for data.
505 public void setFocus() {
506 CTabFolder tabFolder
= fTabFolder
;
507 if (tabFolder
!= null && !(tabFolder
.isDisposed())) {
508 tabFolder
.setFocus();