tmf: TmfTraceManager improvements
[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, 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
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;
69
70 import com.google.common.collect.Lists;
71
72 /**
73 * Class that represents the Stream List View. Such a view lists all the
74 * available streams from the current experiment. <br>
75 * <br>
76 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
77 *
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.
80 *
81 * @author Vincent Perot
82 */
83 public class StreamListView extends TmfView {
84
85 /**
86 * The Stream List View ID.
87 */
88 public static final String ID = "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
89
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
105 };
106
107 private static final int[] COLUMN_SIZES =
108 { 75,
109 350,
110 350,
111 110,
112 110,
113 110,
114 110,
115 110,
116 110,
117 180,
118 180,
119 110,
120 110,
121 110 };
122
123 private static final String KEY_PROTOCOL = "$protocol$"; //$NON-NLS-1$
124 private static final String KEY_STREAM = "$stream$"; //$NON-NLS-1$
125
126 private static final String EMPTY_STRING = ""; //$NON-NLS-1$
127
128 private static final long WAIT_TIME = 1000;
129
130 private @Nullable CTabFolder fTabFolder;
131 private @Nullable Map<TmfPcapProtocol, Table> fTableMap;
132
133 private @Nullable TmfPacketStream fCurrentStream;
134 private @Nullable ITmfTrace fCurrentTrace;
135
136 private volatile boolean fStopThread;
137
138 /**
139 * Constructor of the StreamListView class.
140 */
141 public StreamListView() {
142 super(ID);
143 }
144
145 /**
146 * Handler called when an trace is opened.
147 *
148 * @param signal
149 * Contains the information about the selection.
150 */
151 @TmfSignalHandler
152 public void traceOpened(TmfTraceOpenedSignal signal) {
153 fCurrentTrace = signal.getTrace();
154 resetView();
155 queryAnalysis();
156 }
157
158 /**
159 * Handler called when an trace is closed. Checks if the trace is the
160 * current trace and update the view accordingly.
161 *
162 * @param signal
163 * Contains the information about the selection.
164 */
165 @TmfSignalHandler
166 public void traceClosed(TmfTraceClosedSignal signal) {
167 if (fCurrentTrace == signal.getTrace()) {
168 fCurrentTrace = null;
169 resetView();
170 }
171 }
172
173 /**
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.
176 *
177 * @param signal
178 * Contains the information about the selection.
179 */
180 @TmfSignalHandler
181 public void traceSelected(TmfTraceSelectedSignal signal) {
182 if (fCurrentTrace != signal.getTrace()) {
183 fCurrentTrace = signal.getTrace();
184 resetView();
185 queryAnalysis();
186 }
187 }
188
189 private void queryAnalysis() {
190 Thread thread = new Thread(new Runnable() {
191
192 @Override
193 public void run() {
194 ITmfTrace trace = fCurrentTrace;
195 if (trace == null || (!(trace instanceof PcapTrace))) {
196 return;
197 }
198 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
199 if (analysis == null) {
200 return;
201 }
202 while (!analysis.isFinished() && !fStopThread) {
203 updateUI();
204 try {
205 Thread.sleep(WAIT_TIME);
206 } catch (InterruptedException e) {
207 String message = e.getMessage();
208 if (message == null) {
209 message = EMPTY_STRING;
210 }
211 Activator.logError(message, e);
212 return;
213 }
214 }
215 // Update UI one more time (daft punk)
216 if (!fStopThread) {
217 updateUI();
218 }
219
220 }
221 });
222
223 fStopThread = false;
224 thread.start();
225 }
226
227 private void resetView() {
228
229 // Stop thread if needed
230 fStopThread = true;
231
232 // Remove all content in tables
233 final Display display = Display.getDefault();
234 if (display == null || display.isDisposed()) {
235 return;
236 }
237 display.asyncExec(new Runnable() {
238
239 @Override
240 public void run() {
241 if (display.isDisposed()) {
242 return;
243 }
244 Map<TmfPcapProtocol, Table> tableMap = fTableMap;
245 if (tableMap == null) {
246 return;
247 }
248 for (TmfPcapProtocol protocol : tableMap.keySet()) {
249 if (!(tableMap.get(protocol).isDisposed())) {
250 tableMap.get(protocol).removeAll();
251 }
252 }
253 }
254 });
255 }
256
257 private void updateUI() {
258 final Display display = Display.getDefault();
259 if (display == null || display.isDisposed()) {
260 return;
261 }
262 display.asyncExec(new Runnable() {
263
264 @Override
265 public void run() {
266 if (display.isDisposed()) {
267 return;
268 }
269 ITmfTrace trace = fCurrentTrace;
270 if (trace == null) {
271 return;
272 }
273
274 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
275 if (analysis == null) {
276 return;
277 }
278
279 Map<TmfPcapProtocol, Table> tables = fTableMap;
280 if (tables == null) {
281 return;
282 }
283 for (TmfPcapProtocol protocol : tables.keySet()) {
284 if (protocol == null) {
285 throw new IllegalStateException();
286 }
287 TmfPacketStreamBuilder builder = analysis.getBuilder(protocol);
288 if (builder != null && !(tables.get(protocol).isDisposed())) {
289 for (TmfPacketStream stream : builder.getStreams()) {
290
291 TableItem item;
292 if (stream.getID() < tables.get(protocol).getItemCount()) {
293 item = tables.get(protocol).getItem(stream.getID());
294 } else {
295 item = new TableItem(tables.get(protocol), SWT.NONE);
296 }
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);
312 }
313 }
314 }
315 }
316
317 });
318 }
319
320 @Override
321 public void createPartControl(@Nullable Composite parent) {
322 // Initialize
323 fTableMap = new HashMap<>();
324 fCurrentTrace = TmfTraceManager.getInstance().getActiveTrace();
325 fCurrentStream = null;
326
327 // Add a tab folder
328 fTabFolder = new CTabFolder(parent, SWT.NONE);
329 fTabFolder.addSelectionListener(new SelectionAdapter() {
330
331 @Override
332 public void widgetSelected(@Nullable SelectionEvent e) {
333 Map<TmfPcapProtocol, Table> tables = fTableMap;
334 if (tables == null || e == null) {
335 return;
336 }
337 TmfPcapProtocol protocol = (TmfPcapProtocol) e.item.getData(KEY_PROTOCOL);
338 tables.get(protocol).deselectAll();
339 fCurrentStream = null;
340 }
341
342 });
343
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);
353
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]);
359 }
360 item.setControl(table);
361 table.addSelectionListener(new SelectionAdapter() {
362
363 @Override
364 public void widgetSelected(@Nullable SelectionEvent e) {
365 if (e == null) {
366 return;
367 }
368 fCurrentStream = (TmfPacketStream) e.item.getData(KEY_STREAM);
369 }
370
371 });
372
373 Map<TmfPcapProtocol, Table> tables = fTableMap;
374 if (tables == null) {
375 return;
376 }
377
378 tables.put(protocol, table);
379
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() {
385
386 @Override
387 public void handleEvent(@Nullable Event event) {
388 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream);
389 TmfSignalManager.dispatchSignal(signal);
390 }
391 });
392 menuItem = new MenuItem(menu, SWT.PUSH);
393 menuItem.setText(Messages.StreamListView_Clear);
394 menuItem.addListener(SWT.Selection, new Listener() {
395
396 @Override
397 public void handleEvent(@Nullable Event event) {
398 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, null);
399 TmfSignalManager.dispatchSignal(signal);
400
401 }
402 });
403 menuItem = new MenuItem(menu, SWT.PUSH);
404 menuItem.setText(Messages.StreamListView_ExtractAsFilter);
405 menuItem.addListener(SWT.Selection, new Listener() {
406
407 @Override
408 public void handleEvent(@Nullable Event event) {
409 // Generate filter.
410 ITmfFilterTreeNode filter = generateFilter();
411
412 // Update view and XML
413 updateFilters(filter);
414
415 }
416
417 private void updateFilters(@Nullable ITmfFilterTreeNode filter) {
418 if (filter == null) {
419 return;
420 }
421
422 // Update XML
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))) {
428 newFilter = false;
429 break;
430 }
431 }
432 if (newFilter) {
433 filters.add(filter);
434 FilterManager.setSavedFilters(filters.toArray(new ITmfFilterTreeNode[filters.size()]));
435 }
436
437 // Update Filter View
438 try {
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$
447 return;
448 }
449
450 }
451
452 private @Nullable ITmfFilterTreeNode generateFilter() {
453 TmfPacketStream stream = fCurrentStream;
454 if (stream == null) {
455 return null;
456 }
457
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);
462
463 // Second stage - and
464 TmfFilterAndNode and = new TmfFilterAndNode(root);
465
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);
472
473 // Fourth stage - and
474 TmfFilterAndNode andA = new TmfFilterAndNode(or);
475 TmfFilterAndNode andB = new TmfFilterAndNode(or);
476
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());
494
495 return root;
496 }
497 });
498 table.setMenu(menu);
499 }
500 }
501
502 // Ask the analysis for data.
503 queryAnalysis();
504 }
505
506 @Override
507 public void setFocus() {
508 CTabFolder tabFolder = fTabFolder;
509 if (tabFolder != null && !(tabFolder.isDisposed())) {
510 tabFolder.setFocus();
511 }
512 }
513
514 }
This page took 0.043866 seconds and 6 git commands to generate.