Fix custom traces not indexed for wizard output preview table
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / internal / tmf / ui / parsers / custom / CustomXmlTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2010 Ericsson
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 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.ui.parsers.custom;
14
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.RandomAccessFile;
18
19 import javax.xml.parsers.DocumentBuilder;
20 import javax.xml.parsers.DocumentBuilderFactory;
21 import javax.xml.parsers.ParserConfigurationException;
22
23 import org.eclipse.core.resources.IProject;
24 import org.eclipse.core.resources.IResource;
25 import org.eclipse.linuxtools.internal.tmf.ui.Activator;
26 import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputAttribute;
27 import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputElement;
28 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
29 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
30 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
31 import org.eclipse.linuxtools.tmf.core.io.BufferedRandomAccessFile;
32 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
33 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
34 import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
35 import org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer;
36 import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
37 import org.eclipse.linuxtools.tmf.core.trace.TmfLongLocation;
38 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.EntityResolver;
44 import org.xml.sax.ErrorHandler;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
48
49 public class CustomXmlTrace extends TmfTrace implements ITmfEventParser {
50
51 private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation((Long) null);
52 private static final int DEFAULT_CACHE_SIZE = 100;
53
54 private final CustomXmlTraceDefinition fDefinition;
55 private final CustomXmlEventType fEventType;
56 private final InputElement fRecordInputElement;
57 private BufferedRandomAccessFile fFile;
58
59 public CustomXmlTrace(final CustomXmlTraceDefinition definition) {
60 fDefinition = definition;
61 fEventType = new CustomXmlEventType(fDefinition);
62 fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);
63 setCacheSize(DEFAULT_CACHE_SIZE);
64 }
65
66 public CustomXmlTrace(final IResource resource, final CustomXmlTraceDefinition definition, final String path, final int pageSize) throws TmfTraceException {
67 this(definition);
68 setCacheSize((pageSize > 0) ? pageSize : DEFAULT_CACHE_SIZE);
69 initTrace(resource, path, CustomXmlEvent.class);
70 }
71
72 @Override
73 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType) throws TmfTraceException {
74 super.initTrace(resource, path, eventType);
75 try {
76 fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
77 } catch (IOException e) {
78 throw new TmfTraceException(e.getMessage(), e);
79 }
80 }
81
82 @Override
83 public synchronized void dispose() {
84 super.dispose();
85 if (fFile != null) {
86 try {
87 fFile.close();
88 } catch (IOException e) {
89 } finally {
90 fFile = null;
91 }
92 }
93 }
94
95 @Override
96 public ITmfTraceIndexer getIndexer() {
97 return super.getIndexer();
98 }
99
100 @Override
101 public synchronized TmfContext seekEvent(final ITmfLocation location) {
102 final CustomXmlTraceContext context = new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
103 if (NULL_LOCATION.equals(location) || fFile == null) {
104 return context;
105 }
106 try {
107 if (location == null) {
108 fFile.seek(0);
109 } else if (location.getLocationInfo() instanceof Long) {
110 fFile.seek((Long) location.getLocationInfo());
111 }
112 String line;
113 final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$
114 long rawPos = fFile.getFilePointer();
115
116 while ((line = fFile.getNextLine()) != null) {
117 final int idx = line.indexOf(recordElementStart);
118 if (idx != -1) {
119 context.setLocation(new TmfLongLocation(rawPos + idx));
120 return context;
121 }
122 rawPos = fFile.getFilePointer();
123 }
124 return context;
125 } catch (final IOException e) {
126 Activator.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
127 return context;
128 }
129
130 }
131
132 @Override
133 public synchronized TmfContext seekEvent(final double ratio) {
134 if (fFile == null) {
135 return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
136 }
137 try {
138 long pos = Math.round(ratio * fFile.length());
139 while (pos > 0) {
140 fFile.seek(pos - 1);
141 if (fFile.read() == '\n') {
142 break;
143 }
144 pos--;
145 }
146 final ITmfLocation location = new TmfLongLocation(pos);
147 final TmfContext context = seekEvent(location);
148 context.setRank(ITmfContext.UNKNOWN_RANK);
149 return context;
150 } catch (final IOException e) {
151 Activator.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
152 return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
153 }
154 }
155
156 @Override
157 public synchronized double getLocationRatio(final ITmfLocation location) {
158 if (fFile == null) {
159 return 0;
160 }
161 try {
162 if (location.getLocationInfo() instanceof Long) {
163 return (double) ((Long) location.getLocationInfo()) / fFile.length();
164 }
165 } catch (final IOException e) {
166 Activator.getDefault().logError("Error getting location ration. File: " + getPath(), e); //$NON-NLS-1$
167 }
168 return 0;
169 }
170
171 @Override
172 public ITmfLocation getCurrentLocation() {
173 // TODO Auto-generated method stub
174 return null;
175 }
176
177 @Override
178 public synchronized CustomXmlEvent parseEvent(final ITmfContext tmfContext) {
179 ITmfContext context = seekEvent(tmfContext.getLocation());
180 return parse(context);
181 }
182
183 @Override
184 public synchronized CustomXmlEvent getNext(final ITmfContext context) {
185 final ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
186 final CustomXmlEvent event = parse(context);
187 if (event != null) {
188 updateAttributes(savedContext, event.getTimestamp());
189 context.increaseRank();
190 }
191 return event;
192 }
193
194 private synchronized CustomXmlEvent parse(final ITmfContext tmfContext) {
195 if (fFile == null) {
196 return null;
197 }
198 if (!(tmfContext instanceof CustomXmlTraceContext)) {
199 return null;
200 }
201
202 final CustomXmlTraceContext context = (CustomXmlTraceContext) tmfContext;
203 if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
204 return null;
205 }
206
207 CustomXmlEvent event = null;
208 try {
209 if (fFile.getFilePointer() != (Long)context.getLocation().getLocationInfo() + 1)
210 {
211 fFile.seek((Long)context.getLocation().getLocationInfo() + 1); // +1 is for the <
212 }
213 final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$
214 readElement(elementBuffer, fFile);
215 final Element element = parseElementBuffer(elementBuffer);
216
217 event = extractEvent(element, fRecordInputElement);
218 ((StringBuffer) event.getContent().getValue()).append(elementBuffer);
219
220 String line;
221 final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$
222 long rawPos = fFile.getFilePointer();
223
224 while ((line = fFile.getNextLine()) != null) {
225 final int idx = line.indexOf(recordElementStart);
226 if (idx != -1) {
227 context.setLocation(new TmfLongLocation(rawPos + idx));
228 return event;
229 }
230 rawPos = fFile.getFilePointer();
231 }
232 } catch (final IOException e) {
233 Activator.getDefault().logError("Error parsing event. File: " + getPath(), e); //$NON-NLS-1$
234
235 }
236 context.setLocation(NULL_LOCATION);
237 return event;
238 }
239
240 private Element parseElementBuffer(final StringBuffer elementBuffer) {
241 try {
242 final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
243 final DocumentBuilder db = dbf.newDocumentBuilder();
244
245 // The following allows xml parsing without access to the dtd
246 final EntityResolver resolver = new EntityResolver () {
247 @Override
248 public InputSource resolveEntity (final String publicId, final String systemId) {
249 final String empty = ""; //$NON-NLS-1$
250 final ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
251 return new InputSource(bais);
252 }
253 };
254 db.setEntityResolver(resolver);
255
256 // The following catches xml parsing exceptions
257 db.setErrorHandler(new ErrorHandler(){
258 @Override
259 public void error(final SAXParseException saxparseexception) throws SAXException {}
260 @Override
261 public void warning(final SAXParseException saxparseexception) throws SAXException {}
262 @Override
263 public void fatalError(final SAXParseException saxparseexception) throws SAXException {
264 throw saxparseexception;
265 }});
266
267 final Document doc = db.parse(new ByteArrayInputStream(elementBuffer.toString().getBytes()));
268 return doc.getDocumentElement();
269 } catch (final ParserConfigurationException e) {
270 Activator.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
271 } catch (final SAXException e) {
272 Activator.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
273 } catch (final IOException e) {
274 Activator.getDefault().logError("Error parsing element buffer. File: " + getPath(), e); //$NON-NLS-1$
275 }
276 return null;
277 }
278
279 private void readElement(final StringBuffer buffer, final RandomAccessFile raFile) {
280 try {
281 int numRead = 0;
282 boolean startTagClosed = false;
283 int i;
284 while ((i = raFile.read()) != -1) {
285 numRead++;
286 final char c = (char)i;
287 buffer.append(c);
288 if (c == '"') {
289 readQuote(buffer, raFile, '"');
290 } else if (c == '\'') {
291 readQuote(buffer, raFile, '\'');
292 } else if (c == '<') {
293 readElement(buffer, raFile);
294 } else if (c == '/' && numRead == 1) {
295 break; // found "</"
296 } else if (c == '-' && numRead == 3 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("!-")) { //$NON-NLS-1$
297 readComment(buffer, raFile); // found "<!--"
298 } else if (i == '>') {
299 if (buffer.charAt(buffer.length() - 2) == '/') {
300 break; // found "/>"
301 } else if (startTagClosed) {
302 break; // found "<...>...</...>"
303 }
304 else {
305 startTagClosed = true; // found "<...>"
306 }
307 }
308 }
309 return;
310 } catch (final IOException e) {
311 return;
312 }
313 }
314
315 private static void readQuote(final StringBuffer buffer,
316 final RandomAccessFile raFile, final char eq) {
317 try {
318 int i;
319 while ((i = raFile.read()) != -1) {
320 final char c = (char)i;
321 buffer.append(c);
322 if (c == eq)
323 {
324 break; // found matching end-quote
325 }
326 }
327 return;
328 } catch (final IOException e) {
329 return;
330 }
331 }
332
333 private static void readComment(final StringBuffer buffer,
334 final RandomAccessFile raFile) {
335 try {
336 int numRead = 0;
337 int i;
338 while ((i = raFile.read()) != -1) {
339 numRead++;
340 final char c = (char)i;
341 buffer.append(c);
342 if (c == '>' && numRead >= 2 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("--")) //$NON-NLS-1$
343 {
344 break; // found "-->"
345 }
346 }
347 return;
348 } catch (final IOException e) {
349 return;
350 }
351 }
352
353 public static StringBuffer parseElement(final Element parentElement, final StringBuffer buffer) {
354 final NodeList nodeList = parentElement.getChildNodes();
355 String separator = null;
356 for (int i = 0; i < nodeList.getLength(); i++) {
357 final Node node = nodeList.item(i);
358 if (node.getNodeType() == Node.ELEMENT_NODE) {
359 if (separator == null) {
360 separator = " | "; //$NON-NLS-1$
361 } else {
362 buffer.append(separator);
363 }
364 final Element element = (Element) node;
365 if (!element.hasChildNodes()) {
366 buffer.append(element.getNodeName());
367 } else if (element.getChildNodes().getLength() == 1 && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {
368 buffer.append(element.getNodeName() + ":" + element.getFirstChild().getNodeValue().trim()); //$NON-NLS-1$
369 } else {
370 buffer.append(element.getNodeName());
371 buffer.append(" [ "); //$NON-NLS-1$
372 parseElement(element, buffer);
373 buffer.append(" ]"); //$NON-NLS-1$
374 }
375 } else if (node.getNodeType() == Node.TEXT_NODE) {
376 if (node.getNodeValue().trim().length() != 0) {
377 buffer.append(node.getNodeValue().trim());
378 }
379 }
380 }
381 return buffer;
382 }
383
384 public InputElement getRecordInputElement(final InputElement inputElement) {
385 if (inputElement.logEntry) {
386 return inputElement;
387 } else if (inputElement.childElements != null) {
388 for (final InputElement childInputElement : inputElement.childElements) {
389 final InputElement recordInputElement = getRecordInputElement(childInputElement);
390 if (recordInputElement != null) {
391 return recordInputElement;
392 }
393 }
394 }
395 return null;
396 }
397
398 public CustomXmlEvent extractEvent(final Element element, final InputElement inputElement) {
399 final CustomXmlEvent event = new CustomXmlEvent(fDefinition, this, TmfTimestamp.ZERO, "", fEventType,""); //$NON-NLS-1$ //$NON-NLS-2$
400 event.setContent(new CustomEventContent(event, new StringBuffer()));
401 parseElement(element, event, inputElement);
402 return event;
403 }
404
405 private void parseElement(final Element element, final CustomXmlEvent event, final InputElement inputElement) {
406 if (inputElement.inputName != null && !inputElement.inputName.equals(CustomXmlTraceDefinition.TAG_IGNORE)) {
407 event.parseInput(parseElement(element, new StringBuffer()).toString(), inputElement.inputName, inputElement.inputAction, inputElement.inputFormat);
408 }
409 if (inputElement.attributes != null) {
410 for (final InputAttribute attribute : inputElement.attributes) {
411 event.parseInput(element.getAttribute(attribute.attributeName), attribute.inputName, attribute.inputAction, attribute.inputFormat);
412 }
413 }
414 final NodeList childNodes = element.getChildNodes();
415 if (inputElement.childElements != null) {
416 for (int i = 0; i < childNodes.getLength(); i++) {
417 final Node node = childNodes.item(i);
418 if (node instanceof Element) {
419 for (final InputElement child : inputElement.childElements) {
420 if (node.getNodeName().equals(child.elementName)) {
421 parseElement((Element) node, event, child);
422 break;
423 }
424 }
425 }
426 }
427 }
428 return;
429 }
430
431 public CustomTraceDefinition getDefinition() {
432 return fDefinition;
433 }
434
435 /* (non-Javadoc)
436 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
437 */
438 @Override
439 public boolean validate(IProject project, String path) {
440 return fileExists(path);
441 }
442 }
This page took 0.040699 seconds and 6 git commands to generate.