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