164b3c9ddaf858bc83b284f8a0065e4c3f925277
[deliverable/tracecompass.git] / pcap / org.eclipse.tracecompass.tmf.pcap.ui / src / org / eclipse / tracecompass / internal / tmf / pcap / ui / stream / StreamListView.java
1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Vincent Perot - Initial API and implementation
11 * Patrick Tasse - Support aspect filters
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.internal.tmf.pcap.ui.stream;
15
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20
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.ITmfEventAspect;
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;
70
71 import com.google.common.collect.Lists;
72
73 /**
74 * Class that represents the Stream List View. Such a view lists all the
75 * available streams from the current experiment. <br>
76 * <br>
77 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
78 *
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.
81 *
82 * @author Vincent Perot
83 */
84 public class StreamListView extends TmfView {
85
86 /**
87 * The Stream List View ID.
88 */
89 public static final String ID = "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
90
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
106 };
107
108 private static final int[] COLUMN_SIZES =
109 { 75,
110 350,
111 350,
112 110,
113 110,
114 110,
115 110,
116 110,
117 110,
118 180,
119 180,
120 110,
121 110,
122 110 };
123
124 private static final String KEY_PROTOCOL = "$protocol$"; //$NON-NLS-1$
125 private static final String KEY_STREAM = "$stream$"; //$NON-NLS-1$
126
127 private static final String EMPTY_STRING = ""; //$NON-NLS-1$
128
129 private static final long WAIT_TIME = 1000;
130
131 private @Nullable CTabFolder fTabFolder;
132 private @Nullable Map<TmfPcapProtocol, Table> fTableMap;
133
134 private @Nullable TmfPacketStream fCurrentStream;
135 private @Nullable ITmfTrace fCurrentTrace;
136
137 private volatile boolean fStopThread;
138
139 /**
140 * Constructor of the StreamListView class.
141 */
142 public StreamListView() {
143 super(ID);
144 }
145
146 /**
147 * Handler called when an trace is opened.
148 *
149 * @param signal
150 * Contains the information about the selection.
151 */
152 @TmfSignalHandler
153 public void traceOpened(TmfTraceOpenedSignal signal) {
154 fCurrentTrace = signal.getTrace();
155 resetView();
156 queryAnalysis();
157 }
158
159 /**
160 * Handler called when an trace is closed. Checks if the trace is the
161 * current trace and update the view accordingly.
162 *
163 * @param signal
164 * Contains the information about the selection.
165 */
166 @TmfSignalHandler
167 public void traceClosed(TmfTraceClosedSignal signal) {
168 if (fCurrentTrace == signal.getTrace()) {
169 fCurrentTrace = null;
170 resetView();
171 }
172 }
173
174 /**
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.
177 *
178 * @param signal
179 * Contains the information about the selection.
180 */
181 @TmfSignalHandler
182 public void traceSelected(TmfTraceSelectedSignal signal) {
183 if (fCurrentTrace != signal.getTrace()) {
184 fCurrentTrace = signal.getTrace();
185 resetView();
186 queryAnalysis();
187 }
188 }
189
190 private void queryAnalysis() {
191 Thread thread = new Thread(new Runnable() {
192
193 @Override
194 public void run() {
195 ITmfTrace trace = fCurrentTrace;
196 if (trace == null || (!(trace instanceof PcapTrace))) {
197 return;
198 }
199 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
200 if (analysis == null) {
201 return;
202 }
203 while (!analysis.isFinished() && !fStopThread) {
204 updateUI();
205 try {
206 Thread.sleep(WAIT_TIME);
207 } catch (InterruptedException e) {
208 String message = e.getMessage();
209 if (message == null) {
210 message = EMPTY_STRING;
211 }
212 Activator.logError(message, e);
213 return;
214 }
215 }
216 // Update UI one more time (daft punk)
217 if (!fStopThread) {
218 updateUI();
219 }
220
221 }
222 });
223
224 fStopThread = false;
225 thread.start();
226 }
227
228 private void resetView() {
229
230 // Stop thread if needed
231 fStopThread = true;
232
233 // Remove all content in tables
234 final Display display = Display.getDefault();
235 if (display == null || display.isDisposed()) {
236 return;
237 }
238 display.asyncExec(new Runnable() {
239
240 @Override
241 public void run() {
242 if (display.isDisposed()) {
243 return;
244 }
245 Map<TmfPcapProtocol, Table> tableMap = fTableMap;
246 if (tableMap == null) {
247 return;
248 }
249 for (Table table : tableMap.values()) {
250 if (!table.isDisposed()) {
251 table.removeAll();
252 }
253 }
254 }
255 });
256 }
257
258 private void updateUI() {
259 final Display display = Display.getDefault();
260 if (display == null || display.isDisposed()) {
261 return;
262 }
263 display.asyncExec(new Runnable() {
264
265 @Override
266 public void run() {
267 if (display.isDisposed()) {
268 return;
269 }
270 ITmfTrace trace = fCurrentTrace;
271 if (trace == null) {
272 return;
273 }
274
275 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
276 if (analysis == null) {
277 return;
278 }
279
280 Map<TmfPcapProtocol, Table> tables = fTableMap;
281 if (tables == null) {
282 return;
283 }
284 for (Entry<TmfPcapProtocol, Table> protocolEntry : tables.entrySet()) {
285 TmfPcapProtocol protocol = protocolEntry.getKey();
286 if (protocol == null) {
287 throw new IllegalStateException();
288 }
289 TmfPacketStreamBuilder builder = analysis.getBuilder(protocol);
290 Table table = protocolEntry.getValue();
291 if (builder != null && !(table.isDisposed())) {
292 for (TmfPacketStream stream : builder.getStreams()) {
293
294 TableItem item;
295 if (stream.getID() < table.getItemCount()) {
296 item = table.getItem(stream.getID());
297 } else {
298 item = new TableItem(table, SWT.NONE);
299 }
300 item.setText(0, String.valueOf(stream.getID()));
301 item.setText(1, stream.getFirstEndpoint().toString());
302 item.setText(2, stream.getSecondEndpoint().toString());
303 item.setText(3, String.valueOf(stream.getNbPackets()));
304 item.setText(4, String.valueOf(stream.getNbBytes()));
305 item.setText(5, String.valueOf(stream.getNbPacketsAtoB()));
306 item.setText(6, String.valueOf(stream.getNbBytesAtoB()));
307 item.setText(7, String.valueOf(stream.getNbPacketsBtoA()));
308 item.setText(8, String.valueOf(stream.getNbBytesBtoA()));
309 item.setText(9, stream.getStartTime().toString());
310 item.setText(10, stream.getStopTime().toString());
311 item.setText(11, String.format("%.3f", stream.getDuration())); //$NON-NLS-1$
312 item.setText(12, String.format("%.3f", stream.getBPSAtoB())); //$NON-NLS-1$
313 item.setText(13, String.format("%.3f", stream.getBPSBtoA())); //$NON-NLS-1$
314 item.setData(KEY_STREAM, stream);
315 }
316 }
317 }
318 }
319
320 });
321 }
322
323 @Override
324 public void createPartControl(@Nullable Composite parent) {
325 // Initialize
326 fTableMap = new HashMap<>();
327 fCurrentTrace = TmfTraceManager.getInstance().getActiveTrace();
328 fCurrentStream = null;
329
330 // Add a tab folder
331 fTabFolder = new CTabFolder(parent, SWT.NONE);
332 fTabFolder.addSelectionListener(new SelectionAdapter() {
333
334 @Override
335 public void widgetSelected(@Nullable SelectionEvent e) {
336 Map<TmfPcapProtocol, Table> tables = fTableMap;
337 if (tables == null || e == null) {
338 return;
339 }
340 TmfPcapProtocol protocol = (TmfPcapProtocol) e.item.getData(KEY_PROTOCOL);
341 final Table table = tables.get(protocol);
342 if (table != null) {
343 table.deselectAll();
344 }
345 fCurrentStream = null;
346 }
347
348 });
349
350 // Add items and tables for each protocol
351 for (TmfPcapProtocol protocol : TmfPcapProtocol.values()) {
352 if (protocol.supportsStream()) {
353 CTabItem item = new CTabItem(fTabFolder, SWT.NONE);
354 item.setText(protocol.getName());
355 item.setData(KEY_PROTOCOL, protocol);
356 Table table = new Table(fTabFolder, SWT.NONE);
357 table.setHeaderVisible(true);
358 table.setLinesVisible(true);
359
360 // Add columns to table
361 for (int i = 0; i < COLUMN_NAMES.length || i < COLUMN_SIZES.length; i++) {
362 TableColumn column = new TableColumn(table, SWT.NONE);
363 column.setText(COLUMN_NAMES[i]);
364 column.setWidth(COLUMN_SIZES[i]);
365 }
366 item.setControl(table);
367 table.addSelectionListener(new SelectionAdapter() {
368
369 @Override
370 public void widgetSelected(@Nullable SelectionEvent e) {
371 if (e == null) {
372 return;
373 }
374 fCurrentStream = (TmfPacketStream) e.item.getData(KEY_STREAM);
375 }
376
377 });
378
379 Map<TmfPcapProtocol, Table> tables = fTableMap;
380 if (tables == null) {
381 return;
382 }
383
384 tables.put(protocol, table);
385
386 // Add right click menu
387 Menu menu = new Menu(table);
388 MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
389 menuItem.setText(Messages.StreamListView_FollowStream);
390 menuItem.addListener(SWT.Selection, new Listener() {
391
392 @Override
393 public void handleEvent(@Nullable Event event) {
394 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream);
395 TmfSignalManager.dispatchSignal(signal);
396 }
397 });
398 menuItem = new MenuItem(menu, SWT.PUSH);
399 menuItem.setText(Messages.StreamListView_Clear);
400 menuItem.addListener(SWT.Selection, new Listener() {
401
402 @Override
403 public void handleEvent(@Nullable Event event) {
404 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, null);
405 TmfSignalManager.dispatchSignal(signal);
406
407 }
408 });
409 menuItem = new MenuItem(menu, SWT.PUSH);
410 menuItem.setText(Messages.StreamListView_ExtractAsFilter);
411 menuItem.addListener(SWT.Selection, new Listener() {
412
413 @Override
414 public void handleEvent(@Nullable Event event) {
415 // Generate filter.
416 ITmfFilterTreeNode filter = generateFilter();
417
418 // Update view and XML
419 updateFilters(filter);
420
421 }
422
423 private void updateFilters(@Nullable ITmfFilterTreeNode filter) {
424 if (filter == null) {
425 return;
426 }
427
428 // Update XML
429 List<ITmfFilterTreeNode> filters = Lists.newArrayList(FilterManager.getSavedFilters());
430 boolean newFilter = true;
431 for (ITmfFilterTreeNode savedFilter : filters) {
432 // Use toString(explicit) equality because equals() is not implemented
433 if (savedFilter.toString(true).equals(filter.toString(true))) {
434 newFilter = false;
435 break;
436 }
437 }
438 if (newFilter) {
439 filters.add(filter);
440 FilterManager.setSavedFilters(filters.toArray(new ITmfFilterTreeNode[filters.size()]));
441 }
442
443 // Update Filter View
444 try {
445 final IWorkbench wb = PlatformUI.getWorkbench();
446 final IWorkbenchPage activePage = wb.getActiveWorkbenchWindow().getActivePage();
447 IViewPart view = activePage.showView(FilterView.ID);
448 FilterView filterView = (FilterView) view;
449 filterView.addFilter(filter);
450 } catch (final PartInitException e) {
451 TraceUtils.displayErrorMsg(Messages.StreamListView_ExtractAsFilter, "Error opening view " + FilterView.ID + e.getMessage()); //$NON-NLS-1$
452 Activator.logError("Error opening view " + FilterView.ID, e); //$NON-NLS-1$
453 return;
454 }
455
456 }
457
458 private @Nullable ITmfFilterTreeNode generateFilter() {
459 TmfPacketStream stream = fCurrentStream;
460 if (stream == null) {
461 return null;
462 }
463
464 // First stage - root
465 String name = Messages.StreamListView_FilterName_Stream + ' ' + stream.getProtocol().getShortName() + ' ' + stream.getFirstEndpoint()
466 + " <--> " + stream.getSecondEndpoint(); //$NON-NLS-1$
467 TmfFilterNode root = new TmfFilterNode(name);
468
469 // Second stage - and
470 TmfFilterAndNode and = new TmfFilterAndNode(root);
471
472 // Third stage - protocol + or
473 TmfFilterContainsNode protocolFilter = new TmfFilterContainsNode(and);
474 protocolFilter.setEventAspect(ITmfEventAspect.BaseAspects.CONTENTS.forField(stream.getProtocol().getName()));
475 protocolFilter.setTraceTypeId(TmfFilterAspectNode.BASE_ASPECT_ID);
476 protocolFilter.setValue(EMPTY_STRING);
477 TmfFilterOrNode or = new TmfFilterOrNode(and);
478
479 // Fourth stage - and
480 TmfFilterAndNode andA = new TmfFilterAndNode(or);
481 TmfFilterAndNode andB = new TmfFilterAndNode(or);
482
483 // Fourth stage - endpoints
484 TmfFilterContainsNode endpointAAndA = new TmfFilterContainsNode(andA);
485 endpointAAndA.setEventAspect(PcapSourceAspect.INSTANCE);
486 endpointAAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
487 endpointAAndA.setValue(stream.getFirstEndpoint());
488 TmfFilterContainsNode endpointBAndA = new TmfFilterContainsNode(andA);
489 endpointBAndA.setEventAspect(PcapDestinationAspect.INSTANCE);
490 endpointBAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
491 endpointBAndA.setValue(stream.getSecondEndpoint());
492 TmfFilterContainsNode endpointAAndB = new TmfFilterContainsNode(andB);
493 endpointAAndB.setEventAspect(PcapSourceAspect.INSTANCE);
494 endpointAAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
495 endpointAAndB.setValue(stream.getSecondEndpoint());
496 TmfFilterContainsNode endpointBAndB = new TmfFilterContainsNode(andB);
497 endpointBAndB.setEventAspect(PcapDestinationAspect.INSTANCE);
498 endpointBAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
499 endpointBAndB.setValue(stream.getFirstEndpoint());
500
501 return root;
502 }
503 });
504 table.setMenu(menu);
505 }
506 }
507
508 // Ask the analysis for data.
509 queryAnalysis();
510 }
511
512 @Override
513 public void setFocus() {
514 CTabFolder tabFolder = fTabFolder;
515 if (tabFolder != null && !(tabFolder.isDisposed())) {
516 tabFolder.setFocus();
517 }
518 }
519
520 }
This page took 0.070638 seconds and 5 git commands to generate.