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