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