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