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