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
.ArrayList
;
17 import java
.util
.HashMap
;
18 import java
.util
.List
;
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
.TmfEventFieldAspect
;
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
.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
;
71 * Class that represents the Stream List View. Such a view lists all the
72 * available streams from the current experiment. <br>
74 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
76 * FIXME analysis is leaking ressource. Someone I will not name told me not to worry about it since
77 * AnalysisModule will not be autocloseable later.
79 * @author Vincent Perot
81 public class StreamListView
extends TmfView
{
84 * The Stream List View ID.
86 public static final String ID
= "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
88 private static final String
[] COLUMN_NAMES
=
89 { Messages
.StreamListView_ID
,
90 Messages
.StreamListView_EndpointA
,
91 Messages
.StreamListView_EndpointB
,
92 Messages
.StreamListView_TotalPackets
,
93 Messages
.StreamListView_TotalBytes
,
94 Messages
.StreamListView_PacketsAtoB
,
95 Messages
.StreamListView_BytesAtoB
,
96 Messages
.StreamListView_PacketsBtoA
,
97 Messages
.StreamListView_BytesBtoA
,
98 Messages
.StreamListView_StartTime
,
99 Messages
.StreamListView_StopTime
,
100 Messages
.StreamListView_Duration
,
101 Messages
.StreamListView_BPSAtoB
,
102 Messages
.StreamListView_BPSBtoA
105 private static final int[] COLUMN_SIZES
=
121 private static final String KEY_PROTOCOL
= "$protocol$"; //$NON-NLS-1$
122 private static final String KEY_STREAM
= "$stream$"; //$NON-NLS-1$
124 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
126 private static final long WAIT_TIME
= 1000;
128 private @Nullable CTabFolder fTabFolder
;
129 private @Nullable Map
<TmfPcapProtocol
, Table
> fTableMap
;
131 private @Nullable TmfPacketStream fCurrentStream
;
132 private @Nullable ITmfTrace fCurrentTrace
;
134 private volatile boolean fStopThread
;
137 * Constructor of the StreamListView class.
139 public StreamListView() {
144 * Handler called when an trace is opened.
147 * Contains the information about the selection.
150 public void traceOpened(TmfTraceOpenedSignal signal
) {
151 fCurrentTrace
= signal
.getTrace();
157 * Handler called when an trace is closed. Checks if the trace is the
158 * current trace and update the view accordingly.
161 * Contains the information about the selection.
164 public void traceClosed(TmfTraceClosedSignal signal
) {
165 if (fCurrentTrace
== signal
.getTrace()) {
166 fCurrentTrace
= null;
172 * Handler called when an trace is selected. Checks if the trace has changed
173 * and requests the selected trace if it has not yet been cached.
176 * Contains the information about the selection.
179 public void traceSelected(TmfTraceSelectedSignal signal
) {
180 if (fCurrentTrace
!= signal
.getTrace()) {
181 fCurrentTrace
= signal
.getTrace();
187 private void queryAnalysis() {
188 Thread thread
= new Thread(new Runnable() {
192 ITmfTrace trace
= fCurrentTrace
;
193 if (trace
== null || (!(trace
instanceof PcapTrace
))) {
196 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
197 if (analysis
== null) {
200 while (!analysis
.isFinished() && !fStopThread
) {
203 Thread
.sleep(WAIT_TIME
);
204 } catch (InterruptedException e
) {
205 String message
= e
.getMessage();
206 if (message
== null) {
207 message
= EMPTY_STRING
;
209 Activator
.logError(message
, e
);
213 // Update UI one more time (daft punk)
225 private void resetView() {
227 // Stop thread if needed
230 // Remove all content in tables
231 final Display display
= Display
.getDefault();
232 if (display
== null || display
.isDisposed()) {
235 display
.asyncExec(new Runnable() {
239 if (display
.isDisposed()) {
242 Map
<TmfPcapProtocol
, Table
> tableMap
= fTableMap
;
243 if (tableMap
== null) {
246 for (TmfPcapProtocol protocol
: tableMap
.keySet()) {
247 if (!(tableMap
.get(protocol
).isDisposed())) {
248 tableMap
.get(protocol
).removeAll();
255 private void updateUI() {
256 final Display display
= Display
.getDefault();
257 if (display
== null || display
.isDisposed()) {
260 display
.asyncExec(new Runnable() {
264 if (display
.isDisposed()) {
267 ITmfTrace trace
= fCurrentTrace
;
272 StreamListAnalysis analysis
= TmfTraceUtils
.getAnalysisModuleOfClass(trace
, StreamListAnalysis
.class, StreamListAnalysis
.ID
);
273 if (analysis
== null) {
277 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
278 if (tables
== null) {
281 for (TmfPcapProtocol protocol
: tables
.keySet()) {
282 if (protocol
== null) {
283 throw new IllegalStateException();
285 TmfPacketStreamBuilder builder
= analysis
.getBuilder(protocol
);
286 if (builder
!= null && !(tables
.get(protocol
).isDisposed())) {
287 for (TmfPacketStream stream
: builder
.getStreams()) {
290 if (stream
.getID() < tables
.get(protocol
).getItemCount()) {
291 item
= tables
.get(protocol
).getItem(stream
.getID());
293 item
= new TableItem(tables
.get(protocol
), SWT
.NONE
);
295 item
.setText(0, String
.valueOf(stream
.getID()));
296 item
.setText(1, stream
.getFirstEndpoint().toString());
297 item
.setText(2, stream
.getSecondEndpoint().toString());
298 item
.setText(3, String
.valueOf(stream
.getNbPackets()));
299 item
.setText(4, String
.valueOf(stream
.getNbBytes()));
300 item
.setText(5, String
.valueOf(stream
.getNbPacketsAtoB()));
301 item
.setText(6, String
.valueOf(stream
.getNbBytesAtoB()));
302 item
.setText(7, String
.valueOf(stream
.getNbPacketsBtoA()));
303 item
.setText(8, String
.valueOf(stream
.getNbBytesBtoA()));
304 item
.setText(9, stream
.getStartTime().toString());
305 item
.setText(10, stream
.getStopTime().toString());
306 item
.setText(11, String
.format("%.3f", stream
.getDuration())); //$NON-NLS-1$
307 item
.setText(12, String
.format("%.3f", stream
.getBPSAtoB())); //$NON-NLS-1$
308 item
.setText(13, String
.format("%.3f", stream
.getBPSBtoA())); //$NON-NLS-1$
309 item
.setData(KEY_STREAM
, stream
);
319 public void createPartControl(@Nullable Composite parent
) {
321 fTableMap
= new HashMap
<>();
322 fCurrentTrace
= getActiveTrace();
323 fCurrentStream
= null;
326 fTabFolder
= new CTabFolder(parent
, SWT
.NONE
);
327 fTabFolder
.addSelectionListener(new SelectionAdapter() {
330 public void widgetSelected(@Nullable SelectionEvent e
) {
331 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
332 if (tables
== null || e
== null) {
335 TmfPcapProtocol protocol
= (TmfPcapProtocol
) e
.item
.getData(KEY_PROTOCOL
);
336 tables
.get(protocol
).deselectAll();
337 fCurrentStream
= null;
342 // Add items and tables for each protocol
343 for (TmfPcapProtocol protocol
: TmfPcapProtocol
.values()) {
344 if (protocol
.supportsStream()) {
345 CTabItem item
= new CTabItem(fTabFolder
, SWT
.NONE
);
346 item
.setText(protocol
.getName());
347 item
.setData(KEY_PROTOCOL
, protocol
);
348 Table table
= new Table(fTabFolder
, SWT
.NONE
);
349 table
.setHeaderVisible(true);
350 table
.setLinesVisible(true);
352 // Add columns to table
353 for (int i
= 0; i
< COLUMN_NAMES
.length
|| i
< COLUMN_SIZES
.length
; i
++) {
354 TableColumn column
= new TableColumn(table
, SWT
.NONE
);
355 column
.setText(COLUMN_NAMES
[i
]);
356 column
.setWidth(COLUMN_SIZES
[i
]);
358 item
.setControl(table
);
359 table
.addSelectionListener(new SelectionAdapter() {
362 public void widgetSelected(@Nullable SelectionEvent e
) {
366 fCurrentStream
= (TmfPacketStream
) e
.item
.getData(KEY_STREAM
);
371 Map
<TmfPcapProtocol
, Table
> tables
= fTableMap
;
372 if (tables
== null) {
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
> newFilters
= new ArrayList
<>();
422 ITmfFilterTreeNode
[] oldFilters
= FilterManager
.getSavedFilters();
423 for (int i
= 0; i
< oldFilters
.length
; i
++) {
424 newFilters
.add(oldFilters
[i
]);
426 if (!(newFilters
.contains(filter
))) {
427 newFilters
.add(filter
);
428 FilterManager
.setSavedFilters(newFilters
.toArray(new ITmfFilterTreeNode
[newFilters
.size()]));
431 // Update Filter View
433 final IWorkbench wb
= PlatformUI
.getWorkbench();
434 final IWorkbenchPage activePage
= wb
.getActiveWorkbenchWindow().getActivePage();
435 IViewPart view
= activePage
.showView(FilterView
.ID
);
436 FilterView filterView
= (FilterView
) view
;
437 filterView
.addFilter(filter
);
438 } catch (final PartInitException e
) {
439 TraceUtils
.displayErrorMsg(Messages
.StreamListView_ExtractAsFilter
, "Error opening view " + FilterView
.ID
+ e
.getMessage()); //$NON-NLS-1$
440 Activator
.logError("Error opening view " + FilterView
.ID
, e
); //$NON-NLS-1$
446 private @Nullable ITmfFilterTreeNode
generateFilter() {
447 TmfPacketStream stream
= fCurrentStream
;
448 if (stream
== null) {
452 // First stage - root
453 String name
= Messages
.StreamListView_FilterName_Stream
+ ' ' + stream
.getProtocol().getShortName() + ' ' + stream
.getFirstEndpoint()
454 + " <--> " + stream
.getSecondEndpoint(); //$NON-NLS-1$
455 TmfFilterNode root
= new TmfFilterNode(name
);
457 // Second stage - and
458 TmfFilterAndNode and
= new TmfFilterAndNode(root
);
460 // Third stage - protocol + or
461 TmfFilterContainsNode protocolFilter
= new TmfFilterContainsNode(and
);
462 protocolFilter
.setEventAspect(new TmfEventFieldAspect(stream
.getProtocol().getName(), stream
.getProtocol().getName()));
463 protocolFilter
.setTraceTypeId(TmfFilterAspectNode
.EVENT_FIELD_ASPECT_ID
);
464 protocolFilter
.setValue(EMPTY_STRING
);
465 TmfFilterOrNode or
= new TmfFilterOrNode(and
);
467 // Fourth stage - and
468 TmfFilterAndNode andA
= new TmfFilterAndNode(or
);
469 TmfFilterAndNode andB
= new TmfFilterAndNode(or
);
471 // Fourth stage - endpoints
472 TmfFilterContainsNode endpointAAndA
= new TmfFilterContainsNode(andA
);
473 endpointAAndA
.setEventAspect(PcapSourceAspect
.INSTANCE
);
474 endpointAAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
475 endpointAAndA
.setValue(stream
.getFirstEndpoint());
476 TmfFilterContainsNode endpointBAndA
= new TmfFilterContainsNode(andA
);
477 endpointBAndA
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
478 endpointBAndA
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
479 endpointBAndA
.setValue(stream
.getSecondEndpoint());
480 TmfFilterContainsNode endpointAAndB
= new TmfFilterContainsNode(andB
);
481 endpointAAndB
.setEventAspect(PcapSourceAspect
.INSTANCE
);
482 endpointAAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
483 endpointAAndB
.setValue(stream
.getSecondEndpoint());
484 TmfFilterContainsNode endpointBAndB
= new TmfFilterContainsNode(andB
);
485 endpointBAndB
.setEventAspect(PcapDestinationAspect
.INSTANCE
);
486 endpointBAndB
.setTraceTypeId(PcapTrace
.TRACE_TYPE_ID
);
487 endpointBAndB
.setValue(stream
.getFirstEndpoint());
496 // Ask the analysis for data.
501 public void setFocus() {
502 CTabFolder tabFolder
= fTabFolder
;
503 if (tabFolder
!= null && !(tabFolder
.isDisposed())) {
504 tabFolder
.setFocus();