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