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