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