1 /*******************************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
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
10 * Geneviève Bastien - Initial implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.tests
.stubs
.trace
.xml
;
16 import java
.io
.IOException
;
17 import java
.io
.InputStream
;
20 import javax
.xml
.XMLConstants
;
21 import javax
.xml
.transform
.Source
;
22 import javax
.xml
.transform
.stream
.StreamSource
;
23 import javax
.xml
.validation
.Schema
;
24 import javax
.xml
.validation
.SchemaFactory
;
25 import javax
.xml
.validation
.Validator
;
27 import org
.eclipse
.core
.resources
.IProject
;
28 import org
.eclipse
.core
.resources
.IResource
;
29 import org
.eclipse
.core
.runtime
.IStatus
;
30 import org
.eclipse
.core
.runtime
.Status
;
31 import org
.eclipse
.jdt
.annotation
.NonNull
;
32 import org
.eclipse
.osgi
.util
.NLS
;
33 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventType
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEvent
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventField
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventType
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfTraceException
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomEventContent
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlEvent
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfContext
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfContext
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTrace
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.location
.ITmfLocation
;
51 import org
.xml
.sax
.SAXException
;
54 * An XML development trace using a custom XML trace definition and schema.
56 * This class will typically be used to build custom traces to unit test more
57 * complex functionalities like analyzes or to develop and test data-driven
60 * This class wraps a custom XML trace and rewrites the returned events in the
61 * getNext() method so that event's fields are the ones defined in <field ... />
62 * elements instead of those defined in the custom XML parser. This way, each
63 * event can have a different set of fields. This class can, for example, mimic
66 * @author Geneviève Bastien
68 public class TmfXmlTraceStub
extends TmfTrace
{
70 private static final String DEVELOPMENT_TRACE_PARSER_PATH
= "TmfXmlDevelopmentTrace.xml"; //$NON-NLS-1$
71 private static final String DEVELOPMENT_TRACE_XSD
= "TmfXmlDevelopmentTrace.xsd"; //$NON-NLS-1$
72 private static final String EMPTY
= ""; //$NON-NLS-1$
74 /* XML elements and attributes names */
75 private static final String EVENT_NAME_FIELD
= "Message"; //$NON-NLS-1$
76 private static final String FIELD_NAMES_FIELD
= "fields"; //$NON-NLS-1$
77 private static final String SOURCE_FIELD
= "source"; //$NON-NLS-1$
78 private static final String VALUES_FIELD
= "values"; //$NON-NLS-1$
79 private static final String TYPES_FIELD
= "type"; //$NON-NLS-1$
80 private static final String VALUES_SEPARATOR
= " \\| "; //$NON-NLS-1$
81 private static final String TYPE_INTEGER
= "int"; //$NON-NLS-1$
82 private static final String TYPE_LONG
= "long"; //$NON-NLS-1$
84 private final CustomXmlTrace fTrace
;
87 * Constructor. Constructs the custom XML trace with the appropriate
90 public TmfXmlTraceStub() {
92 /* Load custom XML definition */
93 try (InputStream in
= TmfXmlTraceStub
.class.getResourceAsStream(DEVELOPMENT_TRACE_PARSER_PATH
);) {
94 CustomXmlTraceDefinition
[] definitions
= CustomXmlTraceDefinition
.loadAll(in
);
95 if (definitions
.length
== 0) {
96 throw new IllegalStateException("The custom trace definition does not exist"); //$NON-NLS-1$
98 fTrace
= new CustomXmlTrace(definitions
[0]);
99 /* Deregister the custom XML trace */
100 TmfSignalManager
.deregister(fTrace
);
101 this.setParser(fTrace
);
102 } catch (IOException e
) {
103 throw new IllegalStateException("Cannot open the trace parser for development traces"); //$NON-NLS-1$
109 public void initTrace(IResource resource
, String path
, Class
<?
extends ITmfEvent
> type
) throws TmfTraceException
{
110 super.initTrace(resource
, path
, type
);
111 fTrace
.initTrace(resource
, path
, type
);
113 /* Set the start and (current) end times for this trace */
115 ITmfEvent event
= getNext(ctx
);
117 final ITmfTimestamp curTime
= event
.getTimestamp();
118 this.setStartTime(curTime
);
119 this.setEndTime(curTime
);
124 public ITmfLocation
getCurrentLocation() {
125 return fTrace
.getCurrentLocation();
129 public double getLocationRatio(ITmfLocation location
) {
130 return fTrace
.getLocationRatio(location
);
134 public ITmfContext
seekEvent(ITmfLocation location
) {
135 return fTrace
.seekEvent(location
);
139 public ITmfContext
seekEvent(double ratio
) {
140 return fTrace
.seekEvent(ratio
);
144 public IStatus
validate(IProject project
, String path
) {
145 File xmlFile
= new File(path
);
146 if (!xmlFile
.exists() || !xmlFile
.isFile() || !xmlFile
.canRead()) {
147 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, NLS
.bind(org
.eclipse
.tracecompass
.tmf
.tests
.stubs
.trace
.xml
.Messages
.TmfDevelopmentTrace_FileNotFound
, path
));
149 /* Does the XML file validate with the XSD */
150 SchemaFactory schemaFactory
= SchemaFactory
.newInstance(XMLConstants
.W3C_XML_SCHEMA_NS_URI
);
151 Source xmlSource
= new StreamSource(xmlFile
);
154 URL url
= TmfXmlTraceStub
.class.getResource(DEVELOPMENT_TRACE_XSD
);
155 Schema schema
= schemaFactory
.newSchema(url
);
157 Validator validator
= schema
.newValidator();
158 validator
.validate(xmlSource
);
159 } catch (SAXException e
) {
160 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, NLS
.bind(org
.eclipse
.tracecompass
.tmf
.tests
.stubs
.trace
.xml
.Messages
.TmfDevelopmentTrace_ValidationError
, path
), e
);
161 } catch (IOException e
) {
162 return new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, NLS
.bind(org
.eclipse
.tracecompass
.tmf
.tests
.stubs
.trace
.xml
.Messages
.TmfDevelopmentTrace_IoError
, path
), e
);
164 return Status
.OK_STATUS
;
167 private static String
getStringValue(@NonNull ITmfEventField content
, String fieldName
) {
168 ITmfEventField field
= content
.getField(fieldName
);
172 Object val
= field
.getValue();
173 if (!(val
instanceof String
)) {
180 public synchronized ITmfEvent
getNext(ITmfContext context
) {
181 final ITmfContext savedContext
= new TmfContext(context
.getLocation(), context
.getRank());
182 CustomXmlEvent event
= fTrace
.getNext(context
);
187 /* Translate the content of the event */
188 /* The "fields" field contains a | separated list of field names */
189 /* The "values" field contains a | separated list of field values */
190 /* the "type" field contains a | separated list of field types */
191 ITmfEventField content
= event
.getContent();
192 if (content
== null) {
195 String fieldString
= getStringValue(content
, FIELD_NAMES_FIELD
);
196 String valueString
= getStringValue(content
, VALUES_FIELD
);
197 String typeString
= getStringValue(content
, TYPES_FIELD
);
199 String
[] fields
= fieldString
.split(VALUES_SEPARATOR
);
200 String
[] values
= valueString
.split(VALUES_SEPARATOR
);
201 String
[] types
= typeString
.split(VALUES_SEPARATOR
);
202 ITmfEventField
[] fieldsArray
= new TmfEventField
[fields
.length
];
204 for (int i
= 0; i
< fields
.length
; i
++) {
205 String value
= EMPTY
;
206 if (values
.length
> i
) {
210 if (types
.length
> i
) {
218 val
= Integer
.valueOf(value
);
219 } catch (NumberFormatException e
) {
220 Activator
.logError(String
.format("Get next XML event: cannot cast value %s to integer", value
), e
); //$NON-NLS-1$
227 val
= Long
.valueOf(value
);
228 } catch (NumberFormatException e
) {
229 Activator
.logError(String
.format("Get next XML event: cannot cast value %s to long", value
), e
); //$NON-NLS-1$
238 fieldsArray
[i
] = new TmfEventField(fields
[i
], val
, null);
241 /* Create a new event with new fields and name */
242 ITmfEventType customEventType
= event
.getType();
243 TmfEventType eventType
= new TmfEventType(getStringValue(content
, EVENT_NAME_FIELD
), customEventType
.getRootField());
244 ITmfEventField eventFields
= new CustomEventContent(content
.getName(), content
.getValue(), fieldsArray
);
245 TmfEvent newEvent
= new TmfEvent(this, event
.getTimestamp(), getStringValue(content
, SOURCE_FIELD
), eventType
, eventFields
, event
.getReference());
246 updateAttributes(savedContext
, event
.getTimestamp());
247 context
.increaseRank();