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