pcap: Move plugins to their own sub-directory
[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 tables.get(protocol).deselectAll();
342 fCurrentStream = null;
343 }
344
345 });
346
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);
356
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]);
362 }
363 item.setControl(table);
364 table.addSelectionListener(new SelectionAdapter() {
365
366 @Override
367 public void widgetSelected(@Nullable SelectionEvent e) {
368 if (e == null) {
369 return;
370 }
371 fCurrentStream = (TmfPacketStream) e.item.getData(KEY_STREAM);
372 }
373
374 });
375
376 Map<TmfPcapProtocol, Table> tables = fTableMap;
377 if (tables == null) {
378 return;
379 }
380
381 tables.put(protocol, table);
382
383 // Add right click menu
384 Menu menu = new Menu(table);
385 MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
386 menuItem.setText(Messages.StreamListView_FollowStream);
387 menuItem.addListener(SWT.Selection, new Listener() {
388
389 @Override
390 public void handleEvent(@Nullable Event event) {
391 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream);
392 TmfSignalManager.dispatchSignal(signal);
393 }
394 });
395 menuItem = new MenuItem(menu, SWT.PUSH);
396 menuItem.setText(Messages.StreamListView_Clear);
397 menuItem.addListener(SWT.Selection, new Listener() {
398
399 @Override
400 public void handleEvent(@Nullable Event event) {
401 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, null);
402 TmfSignalManager.dispatchSignal(signal);
403
404 }
405 });
406 menuItem = new MenuItem(menu, SWT.PUSH);
407 menuItem.setText(Messages.StreamListView_ExtractAsFilter);
408 menuItem.addListener(SWT.Selection, new Listener() {
409
410 @Override
411 public void handleEvent(@Nullable Event event) {
412 // Generate filter.
413 ITmfFilterTreeNode filter = generateFilter();
414
415 // Update view and XML
416 updateFilters(filter);
417
418 }
419
420 private void updateFilters(@Nullable ITmfFilterTreeNode filter) {
421 if (filter == null) {
422 return;
423 }
424
425 // Update XML
426 List<ITmfFilterTreeNode> filters = Lists.newArrayList(FilterManager.getSavedFilters());
427 boolean newFilter = true;
428 for (ITmfFilterTreeNode savedFilter : filters) {
429 // Use toString(explicit) equality because equals() is not implemented
430 if (savedFilter.toString(true).equals(filter.toString(true))) {
431 newFilter = false;
432 break;
433 }
434 }
435 if (newFilter) {
436 filters.add(filter);
437 FilterManager.setSavedFilters(filters.toArray(new ITmfFilterTreeNode[filters.size()]));
438 }
439
440 // Update Filter View
441 try {
442 final IWorkbench wb = PlatformUI.getWorkbench();
443 final IWorkbenchPage activePage = wb.getActiveWorkbenchWindow().getActivePage();
444 IViewPart view = activePage.showView(FilterView.ID);
445 FilterView filterView = (FilterView) view;
446 filterView.addFilter(filter);
447 } catch (final PartInitException e) {
448 TraceUtils.displayErrorMsg(Messages.StreamListView_ExtractAsFilter, "Error opening view " + FilterView.ID + e.getMessage()); //$NON-NLS-1$
449 Activator.logError("Error opening view " + FilterView.ID, e); //$NON-NLS-1$
450 return;
451 }
452
453 }
454
455 private @Nullable ITmfFilterTreeNode generateFilter() {
456 TmfPacketStream stream = fCurrentStream;
457 if (stream == null) {
458 return null;
459 }
460
461 // First stage - root
462 String name = Messages.StreamListView_FilterName_Stream + ' ' + stream.getProtocol().getShortName() + ' ' + stream.getFirstEndpoint()
463 + " <--> " + stream.getSecondEndpoint(); //$NON-NLS-1$
464 TmfFilterNode root = new TmfFilterNode(name);
465
466 // Second stage - and
467 TmfFilterAndNode and = new TmfFilterAndNode(root);
468
469 // Third stage - protocol + or
470 TmfFilterContainsNode protocolFilter = new TmfFilterContainsNode(and);
471 protocolFilter.setEventAspect(ITmfEventAspect.BaseAspects.CONTENTS.forField(stream.getProtocol().getName()));
472 protocolFilter.setTraceTypeId(TmfFilterAspectNode.BASE_ASPECT_ID);
473 protocolFilter.setValue(EMPTY_STRING);
474 TmfFilterOrNode or = new TmfFilterOrNode(and);
475
476 // Fourth stage - and
477 TmfFilterAndNode andA = new TmfFilterAndNode(or);
478 TmfFilterAndNode andB = new TmfFilterAndNode(or);
479
480 // Fourth stage - endpoints
481 TmfFilterContainsNode endpointAAndA = new TmfFilterContainsNode(andA);
482 endpointAAndA.setEventAspect(PcapSourceAspect.INSTANCE);
483 endpointAAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
484 endpointAAndA.setValue(stream.getFirstEndpoint());
485 TmfFilterContainsNode endpointBAndA = new TmfFilterContainsNode(andA);
486 endpointBAndA.setEventAspect(PcapDestinationAspect.INSTANCE);
487 endpointBAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
488 endpointBAndA.setValue(stream.getSecondEndpoint());
489 TmfFilterContainsNode endpointAAndB = new TmfFilterContainsNode(andB);
490 endpointAAndB.setEventAspect(PcapSourceAspect.INSTANCE);
491 endpointAAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
492 endpointAAndB.setValue(stream.getSecondEndpoint());
493 TmfFilterContainsNode endpointBAndB = new TmfFilterContainsNode(andB);
494 endpointBAndB.setEventAspect(PcapDestinationAspect.INSTANCE);
495 endpointBAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
496 endpointBAndB.setValue(stream.getFirstEndpoint());
497
498 return root;
499 }
500 });
501 table.setMenu(menu);
502 }
503 }
504
505 // Ask the analysis for data.
506 queryAnalysis();
507 }
508
509 @Override
510 public void setFocus() {
511 CTabFolder tabFolder = fTabFolder;
512 if (tabFolder != null && !(tabFolder.isDisposed())) {
513 tabFolder.setFocus();
514 }
515 }
516
517 }
This page took 0.054323 seconds and 5 git commands to generate.