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