e562fd880e6f232d9669e073e17fc10654222ded
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / parsers / custom / CustomXmlTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2010, 2016 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 * Bernd Hufmann - Add trace type id handling
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.tmf.core.parsers.custom;
15
16 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.RandomAccessFile;
22 import java.nio.ByteBuffer;
23
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.parsers.DocumentBuilderFactory;
26 import javax.xml.parsers.ParserConfigurationException;
27
28 import org.eclipse.core.resources.IProject;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.Status;
32 import org.eclipse.jdt.annotation.NonNull;
33 import org.eclipse.tracecompass.internal.tmf.core.Activator;
34 import org.eclipse.tracecompass.internal.tmf.core.parsers.custom.CustomEventAspects;
35 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
36 import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
37 import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
38 import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
39 import org.eclipse.tracecompass.tmf.core.io.BufferedRandomAccessFile;
40 import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition.Tag;
41 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
42 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
43 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
44 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
45 import org.eclipse.tracecompass.tmf.core.trace.TmfContext;
46 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
47 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
48 import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
49 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
50 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
51 import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
52 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
53 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
54 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
55 import org.eclipse.tracecompass.tmf.core.trace.location.TmfLongLocation;
56 import org.w3c.dom.Document;
57 import org.w3c.dom.Element;
58 import org.w3c.dom.Node;
59 import org.w3c.dom.NodeList;
60 import org.xml.sax.EntityResolver;
61 import org.xml.sax.ErrorHandler;
62 import org.xml.sax.InputSource;
63 import org.xml.sax.SAXException;
64 import org.xml.sax.SAXParseException;
65
66 /**
67 * Trace object for custom XML trace parsers.
68 *
69 * @author Patrick Tassé
70 */
71 public class CustomXmlTrace extends TmfTrace implements ITmfPersistentlyIndexable {
72
73 private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation(-1L);
74 private static final int DEFAULT_CACHE_SIZE = 100;
75 private static final int MAX_LINES = 100;
76 private static final int CONFIDENCE = 100;
77
78 private final CustomXmlTraceDefinition fDefinition;
79 private final ITmfEventField fRootField;
80 private final CustomXmlInputElement fRecordInputElement;
81 private BufferedRandomAccessFile fFile;
82 private final @NonNull String fTraceTypeId;
83
84 private static final char SEPARATOR = ':';
85 private static final String CUSTOM_XML_TRACE_TYPE_PREFIX = "custom.xml.trace" + SEPARATOR; //$NON-NLS-1$
86 private static final String LINUX_TOOLS_CUSTOM_XML_TRACE_TYPE_PREFIX = "org.eclipse.linuxtools.tmf.core.parsers.custom.CustomXmlTrace" + SEPARATOR; //$NON-NLS-1$
87 private static final String EARLY_TRACE_COMPASS_CUSTOM_XML_TRACE_TYPE_PREFIX = "org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTrace" + SEPARATOR; //$NON-NLS-1$
88
89 /**
90 * Basic constructor
91 *
92 * @param definition
93 * Trace definition
94 */
95 public CustomXmlTrace(final CustomXmlTraceDefinition definition) {
96 fDefinition = definition;
97 fRootField = CustomEventType.getRootField(definition);
98 fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);
99 fTraceTypeId = buildTraceTypeId(definition.categoryName, definition.definitionName);
100 setCacheSize(DEFAULT_CACHE_SIZE);
101 }
102
103 /**
104 * Full constructor
105 *
106 * @param resource
107 * Trace resource
108 * @param definition
109 * Trace definition
110 * @param path
111 * Path to the trace/log file
112 * @param pageSize
113 * Page size to use
114 * @throws TmfTraceException
115 * If the trace/log couldn't be opened
116 */
117 public CustomXmlTrace(final IResource resource,
118 final CustomXmlTraceDefinition definition, final String path,
119 final int pageSize) throws TmfTraceException {
120 this(definition);
121 setCacheSize((pageSize > 0) ? pageSize : DEFAULT_CACHE_SIZE);
122 initTrace(resource, path, CustomXmlEvent.class);
123 }
124
125 @Override
126 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType) throws TmfTraceException {
127 super.initTrace(resource, path, eventType);
128 initFile();
129 }
130
131 private void initFile() throws TmfTraceException {
132 closeFile();
133 try {
134 fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
135 } catch (IOException e) {
136 throw new TmfTraceException(e.getMessage(), e);
137 }
138 }
139
140 @Override
141 public synchronized void dispose() {
142 super.dispose();
143 closeFile();
144 }
145
146 private void closeFile() {
147 if (fFile != null) {
148 try {
149 fFile.close();
150 } catch (IOException e) {
151 } finally {
152 fFile = null;
153 }
154 }
155 }
156
157 @Override
158 public ITmfTraceIndexer getIndexer() {
159 return super.getIndexer();
160 }
161
162 @Override
163 public Iterable<ITmfEventAspect<?>> getEventAspects() {
164 return CustomEventAspects.generateAspects(fDefinition);
165 }
166
167 @Override
168 public synchronized TmfContext seekEvent(final ITmfLocation location) {
169 final CustomXmlTraceContext context = new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
170 if (NULL_LOCATION.equals(location) || fFile == null) {
171 return context;
172 }
173 try {
174 if (location == null) {
175 fFile.seek(0);
176 } else if (location.getLocationInfo() instanceof Long) {
177 fFile.seek((Long) location.getLocationInfo());
178 }
179 long rawPos = fFile.getFilePointer();
180 String line = fFile.getNextLine();
181 while (line != null) {
182 final int idx = indexOfElement(fRecordInputElement.getElementName(), line, 0);
183 if (idx != -1) {
184 context.setLocation(new TmfLongLocation(rawPos + idx));
185 return context;
186 }
187 rawPos = fFile.getFilePointer();
188 line = fFile.getNextLine();
189 }
190 return context;
191 } catch (final IOException e) {
192 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
193 return context;
194 }
195
196 }
197
198 @Override
199 public synchronized TmfContext seekEvent(final double ratio) {
200 if (fFile == null) {
201 return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
202 }
203 try {
204 long pos = Math.round(ratio * fFile.length());
205 while (pos > 0) {
206 fFile.seek(pos - 1);
207 if (fFile.read() == '\n') {
208 break;
209 }
210 pos--;
211 }
212 final ITmfLocation location = new TmfLongLocation(pos);
213 final TmfContext context = seekEvent(location);
214 context.setRank(ITmfContext.UNKNOWN_RANK);
215 return context;
216 } catch (final IOException e) {
217 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
218 return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
219 }
220 }
221
222 @Override
223 public synchronized double getLocationRatio(final ITmfLocation location) {
224 if (fFile == null) {
225 return 0;
226 }
227 try {
228 if (location.getLocationInfo() instanceof Long) {
229 return ((Long) location.getLocationInfo()).doubleValue() / fFile.length();
230 }
231 } catch (final IOException e) {
232 Activator.logError("Error getting location ration. File: " + getPath(), e); //$NON-NLS-1$
233 }
234 return 0;
235 }
236
237 @Override
238 public ITmfLocation getCurrentLocation() {
239 // TODO Auto-generated method stub
240 return null;
241 }
242
243 @Override
244 public synchronized CustomXmlEvent parseEvent(final ITmfContext tmfContext) {
245 ITmfContext context = seekEvent(tmfContext.getLocation());
246 return parse(context);
247 }
248
249 @Override
250 public synchronized CustomXmlEvent getNext(final ITmfContext context) {
251 final ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
252 final CustomXmlEvent event = parse(context);
253 if (event != null) {
254 updateAttributes(savedContext, event);
255 context.increaseRank();
256 }
257 return event;
258 }
259
260 private synchronized CustomXmlEvent parse(final ITmfContext tmfContext) {
261 if (fFile == null) {
262 return null;
263 }
264 if (!(tmfContext instanceof CustomXmlTraceContext)) {
265 return null;
266 }
267
268 final CustomXmlTraceContext context = (CustomXmlTraceContext) tmfContext;
269 if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
270 return null;
271 }
272
273 CustomXmlEvent event = null;
274 try {
275 // Below +1 for the <
276 if (fFile.getFilePointer() != (Long) context.getLocation().getLocationInfo() + 1) {
277 fFile.seek((Long) context.getLocation().getLocationInfo() + 1);
278 }
279 final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$
280 readElement(elementBuffer, fFile);
281 final Element element = parseElementBuffer(elementBuffer);
282
283 event = extractEvent(element, fRecordInputElement);
284 ((StringBuffer) event.getContentValue()).append(elementBuffer);
285
286 long rawPos = fFile.getFilePointer();
287 String line = fFile.getNextLine();
288 while (line != null) {
289 final int idx = indexOfElement(fRecordInputElement.getElementName(), line, 0);
290 if (idx != -1) {
291 context.setLocation(new TmfLongLocation(rawPos + idx));
292 return event;
293 }
294 rawPos = fFile.getFilePointer();
295 line = fFile.getNextLine();
296 }
297 } catch (final IOException e) {
298 Activator.logError("Error parsing event. File: " + getPath(), e); //$NON-NLS-1$
299
300 }
301 context.setLocation(NULL_LOCATION);
302 return event;
303 }
304
305 private Element parseElementBuffer(final StringBuffer elementBuffer) {
306 try {
307 final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
308 final DocumentBuilder db = dbf.newDocumentBuilder();
309
310 // The following allows xml parsing without access to the dtd
311 final EntityResolver resolver = new EntityResolver() {
312 @Override
313 public InputSource resolveEntity(final String publicId, final String systemId) {
314 final String empty = ""; //$NON-NLS-1$
315 final ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
316 return new InputSource(bais);
317 }
318 };
319 db.setEntityResolver(resolver);
320
321 // The following catches xml parsing exceptions
322 db.setErrorHandler(new ErrorHandler() {
323 @Override
324 public void error(final SAXParseException saxparseexception) throws SAXException {
325 }
326
327 @Override
328 public void warning(final SAXParseException saxparseexception) throws SAXException {
329 }
330
331 @Override
332 public void fatalError(final SAXParseException saxparseexception) throws SAXException {
333 throw saxparseexception;
334 }
335 });
336
337 final Document doc = db.parse(new ByteArrayInputStream(elementBuffer.toString().getBytes()));
338 return doc.getDocumentElement();
339 } catch (final ParserConfigurationException e) {
340 Activator.logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
341 } catch (final SAXException e) {
342 Activator.logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
343 } catch (final IOException e) {
344 Activator.logError("Error parsing element buffer. File: " + getPath(), e); //$NON-NLS-1$
345 }
346 return null;
347 }
348
349 private static int indexOfElement(String elementName, String line, int fromIndex) {
350 final String recordElementStart = '<' + elementName;
351 int index = line.indexOf(recordElementStart, fromIndex);
352 if (index == -1) {
353 return index;
354 }
355 int nextCharIndex = index + recordElementStart.length();
356 if (nextCharIndex < line.length()) {
357 char c = line.charAt(nextCharIndex);
358 // Check that the match is not just a substring of another element
359 if (Character.isLetterOrDigit(c)) {
360 return indexOfElement(elementName, line, nextCharIndex);
361 }
362 }
363 return index;
364 }
365
366 private void readElement(final StringBuffer buffer, final RandomAccessFile raFile) {
367 try {
368 int numRead = 0;
369 boolean startTagClosed = false;
370 int i;
371 while ((i = raFile.read()) != -1) {
372 numRead++;
373 final char c = (char) i;
374 buffer.append(c);
375 if (c == '"') {
376 readQuote(buffer, raFile, '"');
377 } else if (c == '\'') {
378 readQuote(buffer, raFile, '\'');
379 } else if (c == '<') {
380 readElement(buffer, raFile);
381 } else if (c == '/' && numRead == 1) {
382 break; // found "</"
383 } else if (c == '-' && numRead == 3 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("!-")) { //$NON-NLS-1$
384 readComment(buffer, raFile); // found "<!--"
385 } else if (i == '>') {
386 if (buffer.charAt(buffer.length() - 2) == '/') {
387 break; // found "/>"
388 } else if (startTagClosed) {
389 break; // found "<...>...</...>"
390 }
391 else {
392 startTagClosed = true; // found "<...>"
393 }
394 }
395 }
396 return;
397 } catch (final IOException e) {
398 return;
399 }
400 }
401
402 private static void readQuote(final StringBuffer buffer,
403 final RandomAccessFile raFile, final char eq) {
404 try {
405 int i;
406 while ((i = raFile.read()) != -1) {
407 final char c = (char) i;
408 buffer.append(c);
409 if (c == eq)
410 {
411 break; // found matching end-quote
412 }
413 }
414 return;
415 } catch (final IOException e) {
416 return;
417 }
418 }
419
420 private static void readComment(final StringBuffer buffer,
421 final RandomAccessFile raFile) {
422 try {
423 int numRead = 0;
424 int i;
425 while ((i = raFile.read()) != -1) {
426 numRead++;
427 final char c = (char) i;
428 buffer.append(c);
429 if (c == '>' && numRead >= 2 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("--")) //$NON-NLS-1$
430 {
431 break; // found "-->"
432 }
433 }
434 return;
435 } catch (final IOException e) {
436 return;
437 }
438 }
439
440 /**
441 * Parse an XML element.
442 *
443 * @param parentElement
444 * The parent element
445 * @param buffer
446 * The contents to parse
447 * @return The parsed content
448 */
449 public static StringBuffer parseElement(final Element parentElement, final StringBuffer buffer) {
450 final NodeList nodeList = parentElement.getChildNodes();
451 String separator = null;
452 for (int i = 0; i < nodeList.getLength(); i++) {
453 final Node node = nodeList.item(i);
454 short nodeType = node.getNodeType();
455 if (nodeType == Node.ELEMENT_NODE) {
456 if (separator == null) {
457 separator = " | "; //$NON-NLS-1$
458 } else {
459 buffer.append(separator);
460 }
461 final Element element = (Element) node;
462 if (!element.hasChildNodes()) {
463 buffer.append(element.getNodeName());
464 } else if (element.getChildNodes().getLength() == 1 && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {
465 buffer.append(element.getNodeName());
466 buffer.append(':');
467 buffer.append(element.getFirstChild().getNodeValue().trim());
468 } else {
469 buffer.append(element.getNodeName());
470 buffer.append(" [ "); //$NON-NLS-1$
471 parseElement(element, buffer);
472 buffer.append(" ]"); //$NON-NLS-1$
473 }
474 } else if ((nodeType == Node.TEXT_NODE) && (!node.getNodeValue().trim().isEmpty())) {
475 buffer.append(node.getNodeValue().trim());
476 }
477 }
478 return buffer;
479 }
480
481 /**
482 * Get an input element if it is a valid record input. If not, we will look
483 * into its children for valid inputs.
484 *
485 * @param inputElement
486 * The main element to check for.
487 * @return The record element
488 */
489 public CustomXmlInputElement getRecordInputElement(final CustomXmlInputElement inputElement) {
490 if (inputElement.isLogEntry()) {
491 return inputElement;
492 } else if (inputElement.getChildElements() != null) {
493 for (final CustomXmlInputElement childInputElement : inputElement.getChildElements()) {
494 final CustomXmlInputElement recordInputElement = getRecordInputElement(childInputElement);
495 if (recordInputElement != null) {
496 return recordInputElement;
497 }
498 }
499 }
500 return null;
501 }
502
503 /**
504 * Extract a trace event from an XML element.
505 *
506 * @param element
507 * The element
508 * @param inputElement
509 * The input element
510 * @return The extracted event
511 */
512 public CustomXmlEvent extractEvent(final Element element, final CustomXmlInputElement inputElement) {
513 CustomXmlEventType eventType = new CustomXmlEventType(checkNotNull(fDefinition.definitionName), fRootField);
514 final CustomXmlEvent event = new CustomXmlEvent(fDefinition, this, TmfTimestamp.ZERO, eventType);
515 event.setContent(new CustomEventContent(event, new StringBuffer()));
516 parseElement(element, event, inputElement);
517 return event;
518 }
519
520 private void parseElement(final Element element, final CustomXmlEvent event, final CustomXmlInputElement inputElement) {
521 String eventType = inputElement.getEventType();
522 if (eventType != null && event.getType() instanceof CustomEventType) {
523 ((CustomEventType) event.getType()).setName(eventType);
524 }
525 if (!inputElement.getInputTag().equals(Tag.IGNORE)) {
526 event.parseInput(parseElement(element, new StringBuffer()).toString(), inputElement.getInputTag(), inputElement.getInputName(), inputElement.getInputAction(), inputElement.getInputFormat());
527 }
528 if (inputElement.getAttributes() != null) {
529 for (final CustomXmlInputAttribute attribute : inputElement.getAttributes()) {
530 event.parseInput(element.getAttribute(attribute.getAttributeName()), attribute.getInputTag(), attribute.getInputName(), attribute.getInputAction(), attribute.getInputFormat());
531 }
532 }
533 final NodeList childNodes = element.getChildNodes();
534 if (inputElement.getChildElements() != null) {
535 for (int i = 0; i < childNodes.getLength(); i++) {
536 final Node node = childNodes.item(i);
537 if (node instanceof Element) {
538 for (final CustomXmlInputElement child : inputElement.getChildElements()) {
539 if (node.getNodeName().equals(child.getElementName())) {
540 parseElement((Element) node, event, child);
541 break;
542 }
543 }
544 }
545 }
546 }
547 return;
548 }
549
550 /**
551 * Retrieve the trace definition.
552 *
553 * @return The trace definition
554 */
555 public CustomTraceDefinition getDefinition() {
556 return fDefinition;
557 }
558
559 /**
560 * {@inheritDoc}
561 * <p>
562 * The default implementation sets the confidence to 100 if any of the first
563 * 100 lines of the file contains a valid record input element, and 0
564 * otherwise.
565 */
566 @Override
567 public IStatus validate(IProject project, String path) {
568 File file = new File(path);
569 if (!file.exists() || !file.isFile() || !file.canRead()) {
570 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CustomTrace_FileNotFound + ": " + path); //$NON-NLS-1$
571 }
572 try {
573 if (!TmfTraceUtils.isText(file)) {
574 return new TraceValidationStatus(0, Activator.PLUGIN_ID);
575 }
576 } catch (IOException e) {
577 Activator.logError("Error validating file: " + path, e); //$NON-NLS-1$
578 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
579 }
580 try (BufferedRandomAccessFile rafile = new BufferedRandomAccessFile(path, "r")) { //$NON-NLS-1$
581 int lineCount = 0;
582 long rawPos = 0;
583 String line = rafile.getNextLine();
584 while ((line != null) && (lineCount++ < MAX_LINES)) {
585 final int idx = indexOfElement(fRecordInputElement.getElementName(), line, 0);
586 if (idx != -1) {
587 rafile.seek(rawPos + idx + 1); // +1 is for the <
588 final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$
589 readElement(elementBuffer, rafile);
590 final Element element = parseElementBuffer(elementBuffer);
591 if (element != null) {
592 rafile.close();
593 return new TraceValidationStatus(CONFIDENCE, Activator.PLUGIN_ID);
594 }
595 }
596 rawPos = rafile.getFilePointer();
597 line = rafile.getNextLine();
598 }
599 } catch (IOException e) {
600 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
601 }
602 return new TraceValidationStatus(0, Activator.PLUGIN_ID);
603 }
604
605 private static int fCheckpointSize = -1;
606
607 @Override
608 public synchronized int getCheckpointSize() {
609 if (fCheckpointSize == -1) {
610 TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
611 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
612 b.clear();
613 c.serialize(b);
614 fCheckpointSize = b.position();
615 }
616
617 return fCheckpointSize;
618 }
619
620 @Override
621 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
622 return new TmfLongLocation(bufferIn);
623 }
624
625 @Override
626 protected ITmfTraceIndexer createIndexer(int interval) {
627 return new TmfBTreeTraceIndexer(this, interval);
628 }
629
630 @Override
631 public String getTraceTypeId() {
632 return fTraceTypeId;
633 }
634
635 /**
636 * Build the trace type id for a custom XML trace
637 *
638 * @param category
639 * the category
640 * @param definitionName
641 * the definition name
642 * @return the trace type id
643 */
644 public static @NonNull String buildTraceTypeId(String category, String definitionName) {
645 return CUSTOM_XML_TRACE_TYPE_PREFIX + category + SEPARATOR + definitionName;
646 }
647
648 /**
649 * Checks whether the given trace type ID is a custom XML trace type ID
650 *
651 * @param traceTypeId
652 * the trace type ID to check
653 * @return <code>true</code> if it's a custom text trace type ID else <code>false</code>
654 */
655 public static boolean isCustomTraceTypeId(@NonNull String traceTypeId) {
656 return traceTypeId.startsWith(CUSTOM_XML_TRACE_TYPE_PREFIX);
657 }
658
659 /**
660 * This methods builds a trace type ID from a given ID taking into
661 * consideration any format changes that were done for the IDs of custom
662 * XML traces. For example, such format change took place when moving to
663 * Trace Compass. Trace type IDs that are part of the plug-in extension for
664 * trace types won't be changed.
665 *
666 * This method is useful for IDs that were persisted in the workspace before
667 * the format changes (e.g. in the persistent properties of a trace
668 * resource).
669 *
670 * It ensures backwards compatibility of the workspace for custom XML
671 * traces.
672 *
673 * @param traceTypeId
674 * the legacy trace type ID
675 * @return the trace type id in Trace Compass format
676 */
677 public static @NonNull String buildCompatibilityTraceTypeId(@NonNull String traceTypeId) {
678 // Handle early Trace Compass custom XML trace type IDs
679 if (traceTypeId.startsWith(EARLY_TRACE_COMPASS_CUSTOM_XML_TRACE_TYPE_PREFIX)) {
680 return CUSTOM_XML_TRACE_TYPE_PREFIX + traceTypeId.substring(EARLY_TRACE_COMPASS_CUSTOM_XML_TRACE_TYPE_PREFIX.length());
681 }
682
683 // Handle Linux Tools custom XML trace type IDs (with and without category)
684 int index = traceTypeId.lastIndexOf(SEPARATOR);
685 if ((index != -1) && (traceTypeId.startsWith(LINUX_TOOLS_CUSTOM_XML_TRACE_TYPE_PREFIX))) {
686 String definitionName = index < traceTypeId.length() ? traceTypeId.substring(index + 1) : ""; //$NON-NLS-1$
687 if (traceTypeId.contains(CustomXmlTrace.class.getSimpleName() + SEPARATOR) && traceTypeId.indexOf(SEPARATOR) == index) {
688 return buildTraceTypeId(CustomXmlTraceDefinition.CUSTOM_XML_CATEGORY, definitionName);
689 }
690 return CUSTOM_XML_TRACE_TYPE_PREFIX + traceTypeId.substring(LINUX_TOOLS_CUSTOM_XML_TRACE_TYPE_PREFIX.length());
691 }
692 return traceTypeId;
693 }
694
695 @TmfSignalHandler
696 @Override
697 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
698 if (signal.getTrace() == this) {
699 try {
700 synchronized (this) {
701 // Reset the file handle in case it has reached the end of the
702 // file already. Otherwise, it will not be able to read new data
703 // pass the previous end.
704 initFile();
705 }
706 } catch (TmfTraceException e) {
707 Activator.logError(e.getLocalizedMessage(), e);
708 }
709 }
710 super.traceRangeUpdated(signal);
711 }
712 }
This page took 0.046482 seconds and 4 git commands to generate.