ss: Replace AttributeNotFoundException with IOOBE for quark parameters
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.ui / src / org / eclipse / tracecompass / internal / tmf / analysis / xml / ui / views / xychart / XmlXYViewer.java
1 /*******************************************************************************
2 * Copyright (c) 2014, 2016 École Polytechnique de Montréal and others.
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 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.xychart;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.regex.Pattern;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
30 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
31 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlLocation;
32 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.readonly.TmfXmlReadOnlyModelFactory;
33 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
34 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
35 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
36 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.Activator;
37 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
38 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.XmlViewInfo;
39 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
40 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
41 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
42 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
43 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
44 import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
45 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
46 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
47 import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
48 import org.w3c.dom.Element;
49
50 /**
51 * Main viewer to display XML-defined xy charts. It uses an XML
52 * {@link TmfXmlUiStrings#XY_VIEW} element from an XML file. This element
53 * defines which entries from the state system will be shown and also gives
54 * additional information on the presentation of the view.
55 *
56 * @author Geneviève Bastien
57 */
58 public class XmlXYViewer extends TmfCommonXLineChartViewer {
59
60 private static final String SPLIT_STRING = "/"; //$NON-NLS-1$
61 /** Timeout between updates in the updateData thread */
62 private static final long BUILD_UPDATE_TIMEOUT = 500;
63
64 private static final Pattern WILDCARD_PATTERN = Pattern.compile("\\*"); //$NON-NLS-1$
65
66 private final ITmfXmlModelFactory fFactory = TmfXmlReadOnlyModelFactory.getInstance();
67 private final Map<Integer, SeriesData> fSeriesData = new HashMap<>();
68
69 private final XmlViewInfo fViewInfo;
70
71 /** XML Model elements to use to create the series */
72 private @Nullable ITmfXmlStateAttribute fDisplay;
73 private @Nullable ITmfXmlStateAttribute fSeriesName;
74 private @Nullable XmlXYEntry fEntry;
75
76 private enum DisplayType {
77 ABSOLUTE,
78 DELTA
79 }
80
81 /**
82 * The information related to one series on the chart
83 */
84 private class SeriesData {
85
86 private final double[] fYValues;
87 private final double @Nullable [] fYAbsoluteValues;
88 private final Integer fDisplayQuark;
89 private final String fName;
90 private final DisplayType fType;
91
92 public SeriesData(int length, int attributeQuark, String seriesName, DisplayType type) {
93 fYValues = new double[length];
94 fDisplayQuark = attributeQuark;
95 fName = seriesName;
96 fType = type;
97 switch (fType) {
98 case DELTA:
99 fYAbsoluteValues = new double[length];
100 break;
101 case ABSOLUTE:
102 default:
103 fYAbsoluteValues = null;
104 break;
105 }
106
107 }
108
109 public double[] getYValues() {
110 return fYValues;
111 }
112
113 public Integer getDisplayQuark() {
114 return fDisplayQuark;
115 }
116
117 public String getSeriesName() {
118 return fName;
119 }
120
121 public void setYValue(int i, double yvalue) {
122 switch (fType) {
123 case DELTA:
124 double[] absoluteVals = fYAbsoluteValues;
125 if (absoluteVals == null) {
126 throw new IllegalStateException();
127 }
128 absoluteVals[i] = yvalue;
129 /*
130 * At the first timestamp, the delta value should be 0 since we
131 * do not have the previous values
132 */
133 double prevValue = yvalue;
134 if (i > 0) {
135 prevValue = absoluteVals[i - 1];
136 }
137 fYValues[i] = yvalue - prevValue;
138 break;
139 case ABSOLUTE:
140 default:
141 fYValues[i] = yvalue;
142 break;
143 }
144
145 }
146 }
147
148 private static class XmlXYEntry implements IXmlStateSystemContainer {
149
150 private final ITmfStateSystem fStateSystem;
151 private final String fPath;
152 private final DisplayType fType;
153
154 public XmlXYEntry(ITmfStateSystem stateSystem, String path, Element entryElement) {
155 fStateSystem = stateSystem;
156 fPath = path;
157 switch (entryElement.getAttribute(TmfXmlUiStrings.DISPLAY_TYPE)) {
158 case TmfXmlUiStrings.DISPLAY_TYPE_DELTA:
159 fType = DisplayType.DELTA;
160 break;
161 case TmfXmlUiStrings.DISPLAY_TYPE_ABSOLUTE:
162 default:
163 fType = DisplayType.ABSOLUTE;
164 break;
165 }
166 }
167
168 @Override
169 public @Nullable String getAttributeValue(@Nullable String name) {
170 return name;
171 }
172
173 @Override
174 public ITmfStateSystem getStateSystem() {
175 return fStateSystem;
176 }
177
178 @Override
179 public @NonNull Iterable<@NonNull TmfXmlLocation> getLocations() {
180 return Collections.EMPTY_SET;
181 }
182
183 public DisplayType getType() {
184 return fType;
185 }
186
187 public List<Integer> getQuarks() {
188 /* Get the list of quarks to process with this path */
189 String[] paths = fPath.split(SPLIT_STRING);
190 List<Integer> quarks = Collections.singletonList(IXmlStateSystemContainer.ROOT_QUARK);
191
192 for (String path : paths) {
193 List<Integer> subQuarks = new LinkedList<>();
194 /* Replace * by .* to have a regex string */
195 String name = WILDCARD_PATTERN.matcher(path).replaceAll(".*"); //$NON-NLS-1$
196 for (int relativeQuark : quarks) {
197 subQuarks.addAll(fStateSystem.getSubAttributes(relativeQuark, false, name));
198 }
199 quarks = subQuarks;
200 }
201 return quarks;
202 }
203 }
204
205 /**
206 * Constructor
207 *
208 * @param parent
209 * parent view
210 * @param viewInfo
211 * The view info object
212 */
213 public XmlXYViewer(@Nullable Composite parent, XmlViewInfo viewInfo) {
214 super(parent, Messages.XmlXYViewer_DefaultViewerTitle, Messages.XmlXYViewer_DefaultXAxis, Messages.XmlXYViewer_DefaultYAxis);
215 fViewInfo = viewInfo;
216 }
217
218 @Override
219 protected void updateData(long start, long end, int nb, @Nullable IProgressMonitor monitor) {
220
221 ITmfXmlStateAttribute display = fDisplay;
222 ITmfXmlStateAttribute seriesNameAttrib = fSeriesName;
223 XmlXYEntry entry = fEntry;
224 if (getTrace() == null || display == null || entry == null) {
225 return;
226 }
227 ITmfStateSystem ss = entry.getStateSystem();
228
229 double[] xvalues = getXAxis(start, end, nb);
230 setXAxis(xvalues);
231
232 boolean complete = false;
233 long currentEnd = start;
234
235 while (!complete && currentEnd < end) {
236 if (monitor != null && monitor.isCanceled()) {
237 return;
238 }
239
240 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
241 currentEnd = ss.getCurrentEndTime();
242 try {
243 List<Integer> quarks = entry.getQuarks();
244 long traceStart = getStartTime();
245 long traceEnd = getEndTime();
246 long offset = this.getTimeOffset();
247
248 /* Initialize quarks and series names */
249 for (int quark : quarks) {
250 String seriesName = null;
251 if (seriesNameAttrib == null) {
252 seriesName = ss.getAttributeName(quark);
253 } else {
254 int seriesNameQuark = seriesNameAttrib.getAttributeQuark(quark, null);
255 try {
256 ITmfStateValue seriesNameValue = ss.querySingleState(start, seriesNameQuark).getStateValue();
257 if (!seriesNameValue.isNull()) {
258 seriesName = seriesNameValue.toString();
259 }
260 if (seriesName == null || seriesName.isEmpty()) {
261 seriesName = ss.getAttributeName(quark);
262 }
263 } catch (TimeRangeException e) {
264 /*
265 * The attribute did not exist at this point, simply
266 * use attribute name as series name
267 */
268 seriesName = ss.getAttributeName(quark);
269 }
270 }
271 fSeriesData.put(quark, new SeriesData(xvalues.length, display.getAttributeQuark(quark, null), seriesName, entry.getType()));
272 }
273 for (int i = 0; i < xvalues.length; i++) {
274 if (monitor != null && monitor.isCanceled()) {
275 return;
276 }
277 double x = xvalues[i];
278 long time = (long) x + offset;
279 // make sure that time is in the trace range after double to
280 // long conversion
281 time = time < traceStart ? traceStart : time;
282 time = time > traceEnd ? traceEnd : time;
283
284 for (int quark : quarks) {
285 double yvalue = 0.0;
286 SeriesData data = checkNotNull(fSeriesData.get(quark));
287 try {
288 ITmfStateValue value = ss.querySingleState(time, data.getDisplayQuark()).getStateValue();
289 switch (value.getType()) {
290 case DOUBLE:
291 yvalue = value.unboxDouble();
292 break;
293 case LONG:
294 yvalue = value.unboxLong();
295 break;
296 case INTEGER:
297 yvalue = value.unboxInt();
298 break;
299 case NULL:
300 case STRING:
301 case CUSTOM:
302 default:
303 break;
304 }
305 data.setYValue(i, yvalue);
306 } catch (TimeRangeException e) {
307 data.setYValue(i, 0);
308 }
309 }
310 }
311 for (int quark : quarks) {
312 SeriesData data = checkNotNull(fSeriesData.get(quark));
313 setSeries(data.getSeriesName(), data.getYValues());
314 }
315 updateDisplay();
316 } catch (StateValueTypeException e) {
317 Activator.logError("Error updating the data of XML XY view", e); //$NON-NLS-1$
318 } catch (StateSystemDisposedException e) {
319 return;
320 }
321 }
322
323 }
324
325 @Override
326 protected void initializeDataSource() {
327 super.initializeDataSource();
328
329 ITmfTrace trace = this.getTrace();
330 if (trace == null) {
331 return;
332 }
333
334 Element viewElement = fViewInfo.getViewElement(TmfXmlUiStrings.XY_VIEW);
335 if (viewElement == null) {
336 return;
337 }
338
339 Iterable<String> analysisIds = fViewInfo.getViewAnalysisIds(viewElement);
340
341 List<ITmfAnalysisModuleWithStateSystems> stateSystemModules = new LinkedList<>();
342 if (!analysisIds.iterator().hasNext()) {
343 /*
344 * No analysis specified, take all state system analysis modules
345 */
346 for (ITmfAnalysisModuleWithStateSystems module : TmfTraceUtils.getAnalysisModulesOfClass(trace, ITmfAnalysisModuleWithStateSystems.class)) {
347 stateSystemModules.add(module);
348 }
349 } else {
350 for (String moduleId : analysisIds) {
351 ITmfAnalysisModuleWithStateSystems module = TmfTraceUtils.getAnalysisModuleOfClass(trace, ITmfAnalysisModuleWithStateSystems.class, moduleId);
352 if (module != null) {
353 stateSystemModules.add(module);
354 }
355 }
356 }
357
358 /** Initialize the data */
359 fDisplay = null;
360 fSeriesName = null;
361 ITmfStateSystem ss = null;
362 fEntry = null;
363
364 /* Schedule all state systems */
365 for (ITmfAnalysisModuleWithStateSystems module : stateSystemModules) {
366 IStatus status = module.schedule();
367 if (!status.isOK()) {
368 return;
369 }
370 if (!module.waitForInitialization()) {
371 return;
372 }
373 for (ITmfStateSystem ssq : module.getStateSystems()) {
374 ss = ssq;
375 break;
376 }
377 }
378 if (ss == null) {
379 return;
380 }
381
382 /*
383 * Initialize state attributes. There should be only one entry element
384 * for XY charts.
385 */
386 List<Element> entries = XmlUtils.getChildElements(viewElement, TmfXmlUiStrings.ENTRY_ELEMENT);
387 Element entryElement = entries.get(0);
388 String path = entryElement.getAttribute(TmfXmlUiStrings.PATH);
389 if (path.isEmpty()) {
390 path = TmfXmlStrings.WILDCARD;
391 }
392 XmlXYEntry entry = new XmlXYEntry(ss, path, entryElement);
393 fEntry = entry;
394
395 /* Get the display element to use */
396 List<@NonNull Element> displayElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.DISPLAY_ELEMENT);
397 if (displayElements.isEmpty()) {
398 Activator.logWarning(String.format("XML view: entry for %s should have a display element", path)); //$NON-NLS-1$
399 return;
400 }
401 Element displayElement = displayElements.get(0);
402 fDisplay = fFactory.createStateAttribute(displayElement, entry);
403
404 /* Get the series name element to use */
405 List<Element> seriesNameElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.NAME_ELEMENT);
406 if (!seriesNameElements.isEmpty()) {
407 Element seriesNameElement = seriesNameElements.get(0);
408 fSeriesName = fFactory.createStateAttribute(seriesNameElement, entry);
409 }
410
411 }
412
413 /**
414 * Tells the viewer that the view info has been updated and the viewer needs
415 * to be reinitialized
416 */
417 public void viewInfoUpdated() {
418 reinitialize();
419 }
420
421 }
This page took 0.042363 seconds and 5 git commands to generate.