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