timing.core: Add local statistics to the latency statistics
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core.tests / stubs / org / eclipse / tracecompass / tmf / tests / stubs / trace / xml / TmfXmlTraceStub.java
CommitLineData
1d8ab692 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2014, 2015 École Polytechnique de Montréal
1d8ab692
GB
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 implementation
a62b0a0d 11 * Patrick Tasse - Dispose wrapped trace
1d8ab692
GB
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.tests.stubs.trace.xml;
1d8ab692 15
fafdd006 16import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
ec52ed4a 17import static org.junit.Assert.fail;
fafdd006 18
1d8ab692
GB
19import java.io.File;
20import java.io.IOException;
21import java.io.InputStream;
22import java.net.URL;
69ff4f26 23import java.util.Collection;
c0d85d59 24import java.util.HashSet;
b405ad64
JCK
25import java.util.Optional;
26import java.util.stream.StreamSupport;
1d8ab692
GB
27
28import javax.xml.XMLConstants;
29import javax.xml.transform.Source;
30import javax.xml.transform.stream.StreamSource;
31import javax.xml.validation.Schema;
32import javax.xml.validation.SchemaFactory;
33import javax.xml.validation.Validator;
34
35import org.eclipse.core.resources.IProject;
36import org.eclipse.core.resources.IResource;
ec52ed4a 37import org.eclipse.core.runtime.IPath;
1d8ab692
GB
38import org.eclipse.core.runtime.IStatus;
39import org.eclipse.core.runtime.Status;
d12b792b 40import org.eclipse.jdt.annotation.DefaultLocation;
b405ad64 41import org.eclipse.jdt.annotation.NonNull;
d12b792b 42import org.eclipse.jdt.annotation.NonNullByDefault;
69ff4f26 43import org.eclipse.jdt.annotation.Nullable;
1d8ab692 44import org.eclipse.osgi.util.NLS;
2bdf0193 45import org.eclipse.tracecompass.internal.tmf.core.Activator;
b405ad64 46import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
2bdf0193
AM
47import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
48import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
49import org.eclipse.tracecompass.tmf.core.event.ITmfEventType;
50import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
51import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
52import org.eclipse.tracecompass.tmf.core.event.TmfEventType;
69ff4f26 53import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
b405ad64 54import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects;
40dfafb3 55import org.eclipse.tracecompass.tmf.core.event.aspect.TmfContentFieldAspect;
69ff4f26 56import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
2bdf0193
AM
57import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
58import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomEventContent;
59import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlEvent;
60import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTrace;
61import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTraceDefinition;
62import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
63import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
b2c971ec 64import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
2bdf0193
AM
65import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
66import org.eclipse.tracecompass.tmf.core.trace.TmfContext;
67import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
0e564353
PT
68import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
69import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
2bdf0193 70import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
1d8ab692
GB
71import org.xml.sax.SAXException;
72
69ff4f26 73import com.google.common.collect.ImmutableList;
b405ad64 74import com.google.common.collect.Iterables;
69ff4f26 75
1d8ab692
GB
76/**
77 * An XML development trace using a custom XML trace definition and schema.
78 *
79 * This class will typically be used to build custom traces to unit test more
80 * complex functionalities like analyzes or to develop and test data-driven
81 * analyzes.
82 *
83 * This class wraps a custom XML trace and rewrites the returned events in the
84 * getNext() method so that event's fields are the ones defined in <field ... />
85 * elements instead of those defined in the custom XML parser. This way, each
86 * event can have a different set of fields. This class can, for example, mimic
87 * a CTF trace.
88 *
89 * @author Geneviève Bastien
90 */
91public class TmfXmlTraceStub extends TmfTrace {
92
93 private static final String DEVELOPMENT_TRACE_PARSER_PATH = "TmfXmlDevelopmentTrace.xml"; //$NON-NLS-1$
94 private static final String DEVELOPMENT_TRACE_XSD = "TmfXmlDevelopmentTrace.xsd"; //$NON-NLS-1$
95 private static final String EMPTY = ""; //$NON-NLS-1$
96
97 /* XML elements and attributes names */
98 private static final String EVENT_NAME_FIELD = "Message"; //$NON-NLS-1$
99 private static final String FIELD_NAMES_FIELD = "fields"; //$NON-NLS-1$
1d8ab692
GB
100 private static final String VALUES_FIELD = "values"; //$NON-NLS-1$
101 private static final String TYPES_FIELD = "type"; //$NON-NLS-1$
102 private static final String VALUES_SEPARATOR = " \\| "; //$NON-NLS-1$
103 private static final String TYPE_INTEGER = "int"; //$NON-NLS-1$
104 private static final String TYPE_LONG = "long"; //$NON-NLS-1$
69ff4f26 105 private static final String ASPECT_CPU = "cpu";
1d8ab692 106
12ca2c10
GB
107 private static final Long SECONDS_TO_NS = 1000000000L;
108
0e564353
PT
109 private final CustomXmlTraceDefinition fDefinition;
110 private CustomXmlTrace fTrace;
1d8ab692 111
ec48d248
AM
112 private Collection<ITmfEventAspect<?>> fAspects = TmfTrace.BASE_ASPECTS;
113 private final Collection<ITmfEventAspect<?>> fAdditionalAspects = new HashSet<>();
b405ad64 114 private final Collection<IAnalysisModule> fAdditionalModules = new HashSet<>();
69ff4f26 115
ec52ed4a
GB
116 /**
117 * Validate and initialize a {@link TmfXmlTraceStub} object
118 *
119 * @param absolutePath
120 * The absolute file path of the trace file
121 * @return The trace
122 */
123 public static TmfXmlTraceStub setupTrace(IPath absolutePath) {
124 TmfXmlTraceStub trace = new TmfXmlTraceStub();
125 IStatus status = trace.validate(null, absolutePath.toOSString());
126 if (!status.isOK()) {
127 fail(status.getException().getMessage());
128 }
129 try {
130 trace.initTrace(null, absolutePath.toOSString(), TmfEvent.class);
131 } catch (TmfTraceException e) {
132 fail(e.getMessage());
133 }
134 return trace;
135 }
136
1d8ab692
GB
137 /**
138 * Constructor. Constructs the custom XML trace with the appropriate
139 * definition.
140 */
141 public TmfXmlTraceStub() {
142
143 /* Load custom XML definition */
144 try (InputStream in = TmfXmlTraceStub.class.getResourceAsStream(DEVELOPMENT_TRACE_PARSER_PATH);) {
145 CustomXmlTraceDefinition[] definitions = CustomXmlTraceDefinition.loadAll(in);
0e564353 146 if (definitions.length < 2) {
1d8ab692
GB
147 throw new IllegalStateException("The custom trace definition does not exist"); //$NON-NLS-1$
148 }
0e564353
PT
149 /* The first definition parses the 'set_aspects' event */
150 fTrace = new CustomXmlTrace(definitions[0]) {
151 @Override
152 protected ITmfTraceIndexer createIndexer(int interval) {
153 /* Use the in-memory checkpoint indexer */
154 return new TmfCheckpointIndexer(this, interval);
155 }
156 };
157 /* The second definition parses 'event' trace events */
158 fDefinition = checkNotNull(definitions[1]);
1d8ab692
GB
159 } catch (IOException e) {
160 throw new IllegalStateException("Cannot open the trace parser for development traces"); //$NON-NLS-1$
161 }
162
163 }
164
165 @Override
d12b792b 166 @NonNullByDefault({DefaultLocation.TYPE_ARGUMENT})
69ff4f26 167 public void initTrace(@Nullable IResource resource, @Nullable String path, @Nullable Class<? extends ITmfEvent> type) throws TmfTraceException {
1d8ab692 168 super.initTrace(resource, path, type);
1d8ab692 169 ITmfContext ctx;
0e564353
PT
170
171 /* Initialize and read the trace with the 'set_aspects' definition */
172 TmfSignalManager.deregister(fTrace);
173 fTrace.initTrace(resource, path, type);
174 ctx = seekEvent(0L);
175 /* If a set_aspects event exists, getNext() will process it */
176 getNext(ctx);
177 ctx.dispose();
178 fTrace.dispose();
179
180 /* Initialize a new trace with the trace events definition */
181 fTrace = new CustomXmlTrace(fDefinition);
182 TmfSignalManager.deregister(fTrace);
183 fTrace.initTrace(resource, path, type);
1d8ab692
GB
184 /* Set the start and (current) end times for this trace */
185 ctx = seekEvent(0L);
69ff4f26
GB
186 if (ctx == null) {
187 return;
188 }
1d8ab692
GB
189 ITmfEvent event = getNext(ctx);
190 if (event != null) {
191 final ITmfTimestamp curTime = event.getTimestamp();
192 this.setStartTime(curTime);
193 this.setEndTime(curTime);
194 }
0e564353 195 ctx.dispose();
1d8ab692
GB
196 }
197
a62b0a0d
PT
198 @Override
199 public synchronized void dispose() {
200 super.dispose();
201 fTrace.dispose();
202 }
203
5733be39
AM
204 @Override
205 public @Nullable ITmfEvent parseEvent(@Nullable ITmfContext context) {
206 return fTrace.parseEvent(context);
207 }
208
1d8ab692 209 @Override
69ff4f26 210 public @Nullable ITmfLocation getCurrentLocation() {
1d8ab692
GB
211 return fTrace.getCurrentLocation();
212 }
213
214 @Override
69ff4f26 215 public double getLocationRatio(@Nullable ITmfLocation location) {
1d8ab692
GB
216 return fTrace.getLocationRatio(location);
217 }
218
219 @Override
69ff4f26 220 public @Nullable ITmfContext seekEvent(@Nullable ITmfLocation location) {
1d8ab692
GB
221 return fTrace.seekEvent(location);
222 }
223
224 @Override
69ff4f26 225 public @Nullable ITmfContext seekEvent(double ratio) {
1d8ab692
GB
226 return fTrace.seekEvent(ratio);
227 }
228
229 @Override
69ff4f26 230 public IStatus validate(@Nullable IProject project, @Nullable String path) {
1d8ab692
GB
231 File xmlFile = new File(path);
232 if (!xmlFile.exists() || !xmlFile.isFile() || !xmlFile.canRead()) {
2bdf0193 233 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.Messages.TmfDevelopmentTrace_FileNotFound, path));
1d8ab692
GB
234 }
235 /* Does the XML file validate with the XSD */
236 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
237 Source xmlSource = new StreamSource(xmlFile);
238
239 try {
240 URL url = TmfXmlTraceStub.class.getResource(DEVELOPMENT_TRACE_XSD);
241 Schema schema = schemaFactory.newSchema(url);
242
243 Validator validator = schema.newValidator();
244 validator.validate(xmlSource);
245 } catch (SAXException e) {
2bdf0193 246 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.Messages.TmfDevelopmentTrace_ValidationError, path), e);
1d8ab692 247 } catch (IOException e) {
2bdf0193 248 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.Messages.TmfDevelopmentTrace_IoError, path), e);
1d8ab692 249 }
8cf4e2d7 250 return Status.OK_STATUS;
1d8ab692
GB
251 }
252
69ff4f26 253 private static String getStringValue(ITmfEventField content, String fieldName) {
56e9f830
GB
254 ITmfEventField field = content.getField(fieldName);
255 if (field == null) {
256 return EMPTY;
257 }
258 Object val = field.getValue();
259 if (!(val instanceof String)) {
260 return EMPTY;
261 }
262 return (String) val;
263 }
264
1d8ab692 265 @Override
69ff4f26
GB
266 public synchronized @Nullable ITmfEvent getNext(@Nullable ITmfContext context) {
267 if (context == null) {
268 return null;
269 }
1d8ab692
GB
270 final ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
271 CustomXmlEvent event = fTrace.getNext(context);
272 if (event == null) {
273 return null;
274 }
275
276 /* Translate the content of the event */
277 /* The "fields" field contains a | separated list of field names */
278 /* The "values" field contains a | separated list of field values */
279 /* the "type" field contains a | separated list of field types */
280 ITmfEventField content = event.getContent();
56e9f830
GB
281 if (content == null) {
282 return null;
283 }
69ff4f26 284
56e9f830
GB
285 String fieldString = getStringValue(content, FIELD_NAMES_FIELD);
286 String valueString = getStringValue(content, VALUES_FIELD);
287 String typeString = getStringValue(content, TYPES_FIELD);
1d8ab692
GB
288
289 String[] fields = fieldString.split(VALUES_SEPARATOR);
290 String[] values = valueString.split(VALUES_SEPARATOR);
291 String[] types = typeString.split(VALUES_SEPARATOR);
292 ITmfEventField[] fieldsArray = new TmfEventField[fields.length];
293
294 for (int i = 0; i < fields.length; i++) {
295 String value = EMPTY;
296 if (values.length > i) {
297 value = values[i];
298 }
299 String type = null;
300 if (types.length > i) {
301 type = types[i];
302 }
303 Object val = value;
304 if (type != null) {
305 switch (type) {
306 case TYPE_INTEGER: {
307 try {
308 val = Integer.valueOf(value);
309 } catch (NumberFormatException e) {
310 Activator.logError(String.format("Get next XML event: cannot cast value %s to integer", value), e); //$NON-NLS-1$
311 val = 0;
312 }
313 break;
314 }
315 case TYPE_LONG: {
316 try {
317 val = Long.valueOf(value);
318 } catch (NumberFormatException e) {
319 Activator.logError(String.format("Get next XML event: cannot cast value %s to long", value), e); //$NON-NLS-1$
320 val = 0L;
321 }
322 break;
323 }
324 default:
325 break;
326 }
327 }
fafdd006 328 fieldsArray[i] = new TmfEventField(checkNotNull(fields[i]), val, null);
1d8ab692
GB
329 }
330
c0d85d59
GB
331 /*
332 * Generate the aspects for this trace if it is the 'set_aspects'
333 * definition
334 */
0e564353 335 if (fTrace.getDefinition() != fDefinition) {
69ff4f26 336 generateAspects(fieldsArray);
0e564353 337 return null;
69ff4f26
GB
338 }
339
1d8ab692
GB
340 /* Create a new event with new fields and name */
341 ITmfEventType customEventType = event.getType();
0e564353 342 String eventName = getStringValue(content, EVENT_NAME_FIELD);
69ff4f26 343 TmfEventType eventType = new TmfEventType(eventName, customEventType.getRootField());
1d8ab692 344 ITmfEventField eventFields = new CustomEventContent(content.getName(), content.getValue(), fieldsArray);
12ca2c10
GB
345 /*
346 * TODO: Timestamps for these traces are in nanos, but since the
347 * CustomXmlTrace does not support this format, the timestamp of the
348 * original is in second and we need to convert it. We should do that at
349 * the source when it is supported
350 */
b2c971ec 351 ITmfTimestamp timestamp = TmfTimestamp.fromNanos(event.getTimestamp().getValue() / SECONDS_TO_NS);
12ca2c10 352 TmfEvent newEvent = new TmfEvent(this, ITmfContext.UNKNOWN_RANK, timestamp, eventType, eventFields);
5904c11e 353 updateAttributes(savedContext, event);
1d8ab692
GB
354 return newEvent;
355 }
356
69ff4f26 357 private void generateAspects(ITmfEventField[] fieldsArray) {
ec48d248 358 ImmutableList.Builder<ITmfEventAspect<?>> builder = new ImmutableList.Builder<>();
69ff4f26
GB
359
360 /* Initialize the first default trace aspects */
d187a29b
GB
361 builder.add(TmfBaseAspects.getTimestampAspect());
362 builder.add(TmfBaseAspects.getEventTypeAspect());
69ff4f26
GB
363
364 /* Add custom aspects in between */
365 for (ITmfEventField field : fieldsArray) {
366 String name = field.getName();
ec48d248 367 final ITmfEventAspect<?> aspect = new TmfContentFieldAspect(name, name);
69ff4f26 368 if (name.equals(ASPECT_CPU)) {
40dfafb3
PT
369 builder.add(new TmfCpuAspect() {
370 @Override
371 public @Nullable Integer resolve(ITmfEvent event) {
372 Object result = aspect.resolve(event);
373 if (result instanceof Number) {
374 return ((Number) result).intValue();
375 }
376 return null;
377 }
378 });
379 } else {
380 builder.add(aspect);
69ff4f26 381 }
69ff4f26
GB
382 }
383
384 /* Add the big content aspect */
d187a29b 385 builder.add(TmfBaseAspects.getContentsAspect());
c0d85d59
GB
386 /* Add the additional aspects */
387 builder.addAll(fAdditionalAspects);
872ec368 388 fAspects = builder.build();
69ff4f26
GB
389 }
390
391 @Override
ec48d248 392 public Iterable<ITmfEventAspect<?>> getEventAspects() {
69ff4f26
GB
393 return fAspects;
394 }
395
c0d85d59
GB
396 /**
397 * Adds a new event aspect to this type of trace. Since this trace type is
398 * used to build custom traces that mimic the behavior of real traces, the
399 * required aspects may be missing and this method allows to add them. This
400 * method should be called before calling
401 * {@link #initTrace(IResource, String, Class)} otherwise the additional
402 * aspects will not be picked up when generating the aspects.
403 *
404 * @param aspect
405 * The aspect to have
406 */
ec48d248 407 public void addEventAspect(ITmfEventAspect<?> aspect) {
c0d85d59
GB
408 fAdditionalAspects.add(aspect);
409 }
410
b405ad64
JCK
411 /**
412 * Add an additional new module
413 *
414 * @param module
415 * The new module
416 */
417 public void addAnalysisModule(IAnalysisModule module) {
418 fAdditionalModules.add(module);
419 }
420
421 @Override
422 public Iterable<@NonNull IAnalysisModule> getAnalysisModules() {
423 @NonNull Iterable<IAnalysisModule> modules = super.getAnalysisModules();
424 return checkNotNull(Iterables.concat(modules, fAdditionalModules));
425 }
426
427 @Override
428 public @Nullable IAnalysisModule getAnalysisModule(@Nullable String analysisId) {
429 Iterable<@NonNull IAnalysisModule> modules = getAnalysisModules();
430 Optional<IAnalysisModule> opt = StreamSupport.stream(modules.spliterator(), false).filter(analysis -> analysis.getId().equals(analysisId)).findFirst();
431 return opt.isPresent() ? opt.get() : null;
432 }
1d8ab692 433}
This page took 0.085442 seconds and 5 git commands to generate.