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