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
;
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
.TmfPacketStream
;
37 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.TmfPacketStreamBuilder
;
38 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.aspect
.PcapDestinationAspect
;
39 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.event
.aspect
.PcapSourceAspect
;
40 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.protocol
.TmfPcapProtocol
;
41 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.signal
.TmfPacketStreamSelectedSignal
;
42 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.core
.trace
.PcapTrace
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.pcap
.ui
.Activator
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.event
.aspect
.ITmfEventAspect
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.ITmfFilterTreeNode
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterAndNode
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterAspectNode
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterContainsNode
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterNode
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.filter
.model
.TmfFilterOrNode
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignal
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
59 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
60 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
.TraceUtils
;
61 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
62 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterManager
;
63 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.filter
.FilterView
;
64 import org
.eclipse
.ui
.IViewPart
;
65 import org
.eclipse
.ui
.IWorkbench
;
66 import org
.eclipse
.ui
.IWorkbenchPage
;
67 import org
.eclipse
.ui
.PartInitException
;
68 import org
.eclipse
.ui
.PlatformUI
;
70 import com
.google
.common
.collect
.Lists
;
73 * Class that represents the Stream List View. Such a view lists all the
74 * available streams from the current experiment. <br>
76 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
78 * FIXME analysis is leaking ressource. Someone I will not name told me not to worry about it since
79 * AnalysisModule will not be autocloseable later.
81 * @author Vincent Perot
83 public class StreamListView
extends TmfView
{
86 * The Stream List View ID.
88 public static final String ID
= "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
90 private static final String
[] COLUMN_NAMES
=
91 { Messages
.StreamListView_ID
,
92 Messages
.StreamListView_EndpointA
,
93 Messages
.StreamListView_EndpointB
,
94 Messages
.StreamListView_TotalPackets
,
95 Messages
.StreamListView_TotalBytes
,
96 Messages
.StreamListView_PacketsAtoB
,
97 Messages
.StreamListView_BytesAtoB
,
98 Messages
.StreamListView_PacketsBtoA
,
99 Messages
.StreamListView_BytesBtoA
,
100 Messages
.StreamListView_StartTime
,
101 Messages
.StreamListView_StopTime
,
102 Messages
.StreamListView_Duration
,
103 Messages
.StreamListView_BPSAtoB
,
104 Messages
.StreamListView_BPSBtoA
107 private static final int[] COLUMN_SIZES
=
123 private static final String KEY_PROTOCOL
= "$protocol$"; //$NON-NLS-1$
124 private static final String KEY_STREAM
= "$stream$"; //$NON-NLS-1$
126 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
128 private static final long WAIT_TIME
= 1000;
130 private @Nullable CTabFolder fTabFolder
;
131 private @Nullable Map
<TmfPcapProtocol
, Table
> fTableMap
;
133 private @Nullable TmfPacketStream fCurrentStream
;
134 private @Nullable ITmfTrace fCurrentTrace
;
136 private volatile boolean fStopThread
;
139 * Constructor of the StreamListView class.
141 public StreamListView() {
146 * Handler called when an trace is opened.
149 * Contains the information about the selection.
152 public void traceOpened(TmfTraceOpenedSignal signal
) {
153 fCurrentTrace
= signal
.getTrace();
159 * Handler called when an trace is closed. Checks if the trace is the
160 * current trace and update the view accordingly.
163 * Contains the information about the selection.
166 public void traceClosed(TmfTraceClosedSignal signal
) {
167 if (fCurrentTrace
== signal
.getTrace()) {
168 fCurrentTrace
= null;
174 * Handler called when an trace is selected. Checks if the trace has changed
175 * and requests the selected trace if it has not yet been cached.
178 * Contains the information about the selection.
181 public void traceSelected(TmfTraceSelectedSignal signal
) {
182 if (fCurrentTrace
!= signal
.getTrace()) {
183 fCurrentTrace
= signal
.getTrace();
189 private void queryAnalysis() {
190 Thread thread
= new Thread(new Runnable() {
194 ITmfTrace trace
= fCurrentTrace
;
195 if (trace
== null || (!(trace
instanceof PcapTrace
))) {
198 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
199 if (analysis
== null) {
202 while (!analysis
.isFinished() && !fStopThread
) {
205 Thread
.sleep(WAIT_TIME
);
206 } catch (InterruptedException e
) {
207 String message
= e
.getMessage();
208 if (message
== null) {
209 message
= EMPTY_STRING
;
211 Activator
.logError(message
, e
);
215 // Update UI one more time (daft punk)
227 private void resetView() {
229 // Stop thread if needed
232 // Remove all content in tables
233 final Display display
= Display
.getDefault();
234 if (display
== null || display
.isDisposed()) {
237 display
.asyncExec(new Runnable() {
241 if (display
.isDisposed()) {
244 Map
<TmfPcapProtocol
, Table
> tableMap
= fTableMap
;
245 if (tableMap
== null) {
248 for (TmfPcapProtocol protocol
: tableMap
.keySet()) {
249 if (!(tableMap
.get(protocol
).isDisposed())) {
250 tableMap
.get(protocol
).removeAll();
257 private void updateUI() {
258 final Display display
= Display
.getDefault();
259 if (display
== null || display
.isDisposed()) {
262 display
.asyncExec(new Runnable() {
266 if (display
.isDisposed()) {
269 ITmfTrace trace
= fCurrentTrace
;
274 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
275 if (analysis
== null) {
279 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
280 if (tables
== null) {
283 for (TmfPcapProtocol protocol
: tables
.keySet()) {
284 if (protocol
== null) {
285 throw new IllegalStateException();
287 TmfPacketStreamBuilder builder
= analysis
.getBuilder(protocol
);
288 if (builder
!= null && !(tables
.get(protocol
).isDisposed())) {
289 for (TmfPacketStream stream
: builder
.getStreams()) {
292 if (stream
.getID() < tables
.get(protocol
).getItemCount()) {
293 item
= tables
.get(protocol
).getItem(stream
.getID());
295 item
= new TableItem(tables
.get(protocol
), 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 fTableMap
= new HashMap
<>();
324 fCurrentTrace
= TmfTraceManager
.getInstance().getActiveTrace();
325 fCurrentStream
= null;
328 fTabFolder
= new CTabFolder(parent
, SWT
.NONE
);
329 fTabFolder
.addSelectionListener(new SelectionAdapter() {
332 public void widgetSelected(@Nullable SelectionEvent e
) {
333 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
334 if (tables
== null || e
== null) {
337 TmfPcapProtocol protocol
= (TmfPcapProtocol
) e
.item
.getData(KEY_PROTOCOL
);
338 tables
.get(protocol
).deselectAll();
339 fCurrentStream
= null;
344 // Add items and tables for each protocol
345 for (TmfPcapProtocol protocol
: TmfPcapProtocol
.values()) {
346 if (protocol
.supportsStream()) {
347 CTabItem item
= new CTabItem(fTabFolder
, SWT
.NONE
);
348 item
.setText(protocol
.getName());
349 item
.setData(KEY_PROTOCOL
, protocol
);
350 Table table
= new Table(fTabFolder
, SWT
.NONE
);
351 table
.setHeaderVisible(true);
352 table
.setLinesVisible(true);
354 // Add columns to table
355 for (int i
= 0; i
< COLUMN_NAMES
.length
|| i
< COLUMN_SIZES
.length
; i
++) {
356 TableColumn column
= new TableColumn(table
, SWT
.NONE
);
357 column
.setText(COLUMN_NAMES
[i
]);
358 column
.setWidth(COLUMN_SIZES
[i
]);
360 item
.setControl(table
);
361 table
.addSelectionListener(new SelectionAdapter() {
364 public void widgetSelected(@Nullable SelectionEvent e
) {
368 fCurrentStream
= (TmfPacketStream
) e
.item
.getData(KEY_STREAM
);
373 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
374 if (tables
== null) {
378 tables
.put(protocol
, table
);
380 // Add right click menu
381 Menu menu
= new Menu(table
);
382 MenuItem menuItem
= new MenuItem(menu
, SWT
.PUSH
);
383 menuItem
.setText(Messages
.StreamListView_FollowStream
);
384 menuItem
.addListener(SWT
.Selection
, new Listener() {
387 public void handleEvent(@Nullable Event event
) {
388 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream
);
389 TmfSignalManager
.dispatchSignal(signal
);
392 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
393 menuItem
.setText(Messages
.StreamListView_Clear
);
394 menuItem
.addListener(SWT
.Selection
, new Listener() {
397 public void handleEvent(@Nullable Event event
) {
398 TmfSignal signal
= new TmfPacketStreamSelectedSignal(this, 0, null);
399 TmfSignalManager
.dispatchSignal(signal
);
403 menuItem
= new MenuItem(menu
, SWT
.PUSH
);
404 menuItem
.setText(Messages
.StreamListView_ExtractAsFilter
);
405 menuItem
.addListener(SWT
.Selection
, new Listener() {
408 public void handleEvent(@Nullable Event event
) {
410 ITmfFilterTreeNode filter
= generateFilter();
412 // Update view and XML
413 updateFilters(filter
);
417 private void updateFilters(@Nullable ITmfFilterTreeNode filter
) {
418 if (filter
== null) {
423 List
<ITmfFilterTreeNode
> filters
= Lists
.newArrayList(FilterManager
.getSavedFilters());
424 boolean newFilter
= true;
425 for (ITmfFilterTreeNode savedFilter
: filters
) {
426 // Use toString(explicit) equality because equals() is not implemented
427 if (savedFilter
.toString(true).equals(filter
.toString(true))) {
434 FilterManager
.setSavedFilters(filters
.toArray(new ITmfFilterTreeNode
[filters
.size()]));
437 // Update Filter View
439 final IWorkbench wb
= PlatformUI
.getWorkbench();
440 final IWorkbenchPage activePage
= wb
.getActiveWorkbenchWindow().getActivePage();
441 IViewPart view
= activePage
.showView(FilterView
.ID
);
442 FilterView filterView
= (FilterView
) view
;
443 filterView
.addFilter(filter
);
444 } catch (final PartInitException e
) {
445 TraceUtils
.displayErrorMsg(Messages
.StreamListView_ExtractAsFilter
, "Error opening view " + FilterView
.ID
+ e
.getMessage()); //$NON-NLS-1$
446 Activator
.logError("Error opening view " + FilterView
.ID
, e
); //$NON-NLS-1$
452 private @Nullable ITmfFilterTreeNode
generateFilter() {
453 TmfPacketStream stream
= fCurrentStream
;
454 if (stream
== null) {
458 // First stage - root
459 String name
= Messages
.StreamListView_FilterName_Stream
+ ' ' + stream
.getProtocol().getShortName() + ' ' + stream
.getFirstEndpoint()
460 + " <--> " + stream
.getSecondEndpoint(); //$NON-NLS-1$
461 TmfFilterNode root
= new TmfFilterNode(name
);
463 // Second stage - and
464 TmfFilterAndNode and
= new TmfFilterAndNode(root
);
466 // Third stage - protocol + or
467 TmfFilterContainsNode protocolFilter
= new TmfFilterContainsNode(and
);
468 protocolFilter
.setEventAspect(ITmfEventAspect
.BaseAspects
.CONTENTS
.forField(stream
.getProtocol().getName()));
469 protocolFilter
.setTraceTypeId(TmfFilterAspectNode
.BASE_ASPECT_ID
);
470 protocolFilter
.setValue(EMPTY_STRING
);
471 TmfFilterOrNode or
= new TmfFilterOrNode(and
);
473 // Fourth stage - and
474 TmfFilterAndNode andA
= new TmfFilterAndNode(or
);
475 TmfFilterAndNode andB
= new TmfFilterAndNode(or
);
477 // Fourth stage - endpoints
478 TmfFilterContainsNode endpointAAndA
= new TmfFilterContainsNode(andA
);
479 endpointAAndA
.setEventAspect(PcapSourceAspect
.INSTANCE
);
480 endpointAAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
481 endpointAAndA
.setValue(stream
.getFirstEndpoint());
482 TmfFilterContainsNode endpointBAndA
= new TmfFilterContainsNode(andA
);
483 endpointBAndA
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
484 endpointBAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
485 endpointBAndA
.setValue(stream
.getSecondEndpoint());
486 TmfFilterContainsNode endpointAAndB
= new TmfFilterContainsNode(andB
);
487 endpointAAndB
.setEventAspect(PcapSourceAspect
.INSTANCE
);
488 endpointAAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
489 endpointAAndB
.setValue(stream
.getSecondEndpoint());
490 TmfFilterContainsNode endpointBAndB
= new TmfFilterContainsNode(andB
);
491 endpointBAndB
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
492 endpointBAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
493 endpointBAndB
.setValue(stream
.getFirstEndpoint());
502 // Ask the analysis for data.
507 public void setFocus() {
508 CTabFolder tabFolder
= fTabFolder
;
509 if (tabFolder
!= null && !(tabFolder
.isDisposed())) {
510 tabFolder
.setFocus();