1 /*******************************************************************************
2 * Copyright (c) 2010, 2016 Ericsson
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
10 * Patrick Tasse - Initial API and implementation
11 * Matthew Khouzam - Add support for default parsers
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.tmf
.core
.parsers
.custom
;
16 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
19 import java
.io
.FileWriter
;
20 import java
.io
.IOException
;
21 import java
.io
.StringWriter
;
22 import java
.util
.ArrayList
;
23 import java
.util
.Arrays
;
24 import java
.util
.Comparator
;
25 import java
.util
.List
;
27 import java
.util
.Map
.Entry
;
29 import java
.util
.TreeSet
;
30 import java
.util
.regex
.Pattern
;
31 import java
.util
.regex
.PatternSyntaxException
;
33 import javax
.xml
.parsers
.DocumentBuilder
;
34 import javax
.xml
.parsers
.DocumentBuilderFactory
;
35 import javax
.xml
.parsers
.ParserConfigurationException
;
36 import javax
.xml
.transform
.OutputKeys
;
37 import javax
.xml
.transform
.Transformer
;
38 import javax
.xml
.transform
.TransformerException
;
39 import javax
.xml
.transform
.TransformerFactory
;
40 import javax
.xml
.transform
.TransformerFactoryConfigurationError
;
41 import javax
.xml
.transform
.dom
.DOMSource
;
42 import javax
.xml
.transform
.stream
.StreamResult
;
44 import org
.eclipse
.core
.runtime
.Platform
;
45 import org
.eclipse
.jdt
.annotation
.NonNull
;
46 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
48 import org
.w3c
.dom
.Document
;
49 import org
.w3c
.dom
.Element
;
50 import org
.w3c
.dom
.Node
;
51 import org
.w3c
.dom
.NodeList
;
52 import org
.xml
.sax
.SAXException
;
55 * Trace definition for custom text traces.
57 * @author Patrick Tassé
59 public class CustomTxtTraceDefinition
extends CustomTraceDefinition
{
62 public List
<InputLine
> inputs
;
65 * Custom text label used internally and therefore should not be
68 public static final String CUSTOM_TXT_CATEGORY
= "Custom Text"; //$NON-NLS-1$
71 /** File name of the default definition file */
72 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
= "custom_txt_default_parsers.xml"; //$NON-NLS-1$
73 /** File name of the definition file */
74 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
= "custom_txt_parsers.xml"; //$NON-NLS-1$
76 /** Path of the definition file */
77 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
=
78 Platform
.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
79 CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
;
80 /** Path of the definition file */
81 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
=
82 Activator
.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
85 * Legacy path to the XML definitions file (in the UI plug-in of linuxtools) TODO Remove
86 * once we feel the transition phase is over.
88 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
=
89 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
90 .append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
91 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
94 * Legacy path to the XML definitions file (in the core plug-in of linuxtools) TODO Remove
95 * once we feel the transition phase is over.
97 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
=
98 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
99 .append("org.eclipse.linuxtools.tmf.core") //$NON-NLS-1$
100 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
102 private static final String CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
= Messages
.CustomTxtTraceDefinition_definitionRootElement
;
103 private static final String DEFINITION_ELEMENT
= Messages
.CustomTxtTraceDefinition_definition
;
104 private static final String CATEGORY_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_category
;
105 private static final String TAG_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_tag
;
106 private static final String NAME_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_name
;
107 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT
= Messages
.CustomTxtTraceDefinition_timestampOutputFormat
;
108 private static final String INPUT_LINE_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputLine
;
109 private static final String CARDINALITY_ELEMENT
= Messages
.CustomTxtTraceDefinition_cardinality
;
110 private static final String MIN_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_min
;
111 private static final String MAX_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_max
;
112 private static final String REGEX_ELEMENT
= Messages
.CustomTxtTraceDefinition_regEx
;
113 private static final String EVENT_TYPE_ELEMENT
= Messages
.CustomTxtTraceDefinition_eventType
;
114 private static final String INPUT_DATA_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputData
;
115 private static final String ACTION_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_action
;
116 private static final String FORMAT_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_format
;
117 private static final String OUTPUT_COLUMN_ELEMENT
= Messages
.CustomTxtTraceDefinition_outputColumn
;
120 * Default constructor.
122 public CustomTxtTraceDefinition() {
123 this(CUSTOM_TXT_CATEGORY
, "", new ArrayList
<InputLine
>(0), new ArrayList
<OutputColumn
>(0), ""); //$NON-NLS-1$ //$NON-NLS-2$
130 * Category of the trace type
132 * Name of the trace type
136 * List of output columns
137 * @param timeStampOutputFormat
138 * The timestamp format to use
140 public CustomTxtTraceDefinition(String category
, String traceType
, List
<InputLine
> inputs
,
141 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
142 this.categoryName
= category
;
143 this.definitionName
= traceType
;
144 this.inputs
= inputs
;
145 this.outputs
= outputs
;
146 this.timeStampOutputFormat
= timeStampOutputFormat
;
150 * Wrapper to store a line of the log file
152 public static class InputLine
{
154 /** Data columns of this line */
155 public List
<InputData
> columns
;
157 /** Cardinality of this line (see {@link Cardinality}) */
158 public Cardinality cardinality
;
161 public InputLine parentInput
;
163 /** Level of this line */
166 /** Next input line in the file */
167 public InputLine nextInput
;
169 /** Children of this line (if one "event" spans many lines) */
170 public List
<InputLine
> childrenInputs
;
172 /** Event type associated with this line
174 public String eventType
;
176 private String regex
;
177 private Pattern pattern
;
180 * Default (empty) constructor.
189 * Cardinality of this line.
195 public InputLine(Cardinality cardinality
, String regex
, List
<InputData
> columns
) {
196 this.cardinality
= cardinality
;
198 this.columns
= columns
;
202 * Set the regex of this input line
207 public void setRegex(String regex
) {
213 * Get the current regex
215 * @return The current regex
217 public String
getRegex() {
222 * Get the Pattern object of this line's regex
224 * @return The Pattern
225 * @throws PatternSyntaxException
226 * If the regex does not parse correctly
228 public Pattern
getPattern() throws PatternSyntaxException
{
229 if (pattern
== null) {
230 pattern
= Pattern
.compile(regex
);
236 * Add a child line to this line.
239 * The child input line
241 public void addChild(InputLine input
) {
242 if (childrenInputs
== null) {
243 childrenInputs
= new ArrayList
<>(1);
244 } else if (childrenInputs
.size() > 0) {
245 InputLine last
= childrenInputs
.get(childrenInputs
.size() - 1);
246 last
.nextInput
= input
;
248 childrenInputs
.add(input
);
249 input
.parentInput
= this;
250 input
.level
= this.level
+ 1;
254 * Set the next input line.
257 * The next input line
259 public void addNext(InputLine input
) {
260 if (parentInput
!= null) {
261 int index
= parentInput
.childrenInputs
.indexOf(this);
262 parentInput
.childrenInputs
.add(index
+ 1, input
);
263 InputLine next
= nextInput
;
265 input
.nextInput
= next
;
267 input
.parentInput
= this.parentInput
;
268 input
.level
= this.level
;
272 * Move this line up in its parent's children.
274 public void moveUp() {
275 if (parentInput
!= null) {
276 int index
= parentInput
.childrenInputs
.indexOf(this);
278 parentInput
.childrenInputs
.add(index
- 1, parentInput
.childrenInputs
.remove(index
));
279 parentInput
.childrenInputs
.get(index
).nextInput
= nextInput
;
280 nextInput
= parentInput
.childrenInputs
.get(index
);
286 * Move this line down in its parent's children.
288 public void moveDown() {
289 if (parentInput
!= null) {
290 int index
= parentInput
.childrenInputs
.indexOf(this);
291 if (index
< parentInput
.childrenInputs
.size() - 1) {
292 parentInput
.childrenInputs
.add(index
+ 1, parentInput
.childrenInputs
.remove(index
));
293 nextInput
= parentInput
.childrenInputs
.get(index
).nextInput
;
294 parentInput
.childrenInputs
.get(index
).nextInput
= this;
300 * Add a data column to this line
305 public void addColumn(InputData column
) {
306 if (columns
== null) {
307 columns
= new ArrayList
<>(1);
313 * Get the next input lines.
316 * The map of line "sets".
317 * @return The next list of lines.
319 public List
<InputLine
> getNextInputs(Map
<InputLine
, Integer
> countMap
) {
320 List
<InputLine
> nextInputs
= new ArrayList
<>();
321 InputLine next
= nextInput
;
322 while (next
!= null) {
323 nextInputs
.add(next
);
324 if (next
.cardinality
.min
> 0) {
327 next
= next
.nextInput
;
329 if (parentInput
!= null && parentInput
.level
> 0) {
330 int parentCount
= checkNotNull(countMap
.get(parentInput
));
331 if (parentCount
< parentInput
.getMaxCount()) {
332 nextInputs
.add(parentInput
);
334 if (parentCount
< parentInput
.getMinCount()) {
337 nextInputs
.addAll(parentInput
.getNextInputs(countMap
));
343 * Get the minimum possible amount of entries.
345 * @return The minimum
347 public int getMinCount() {
348 return cardinality
.min
;
352 * Get the maximum possible amount of entries.
354 * @return The maximum
356 public int getMaxCount() {
357 return cardinality
.max
;
361 public String
toString() {
362 return regex
+ " " + cardinality
; //$NON-NLS-1$
367 * Data column for input lines.
369 public static class InputData
{
371 /** Tag of this input
375 /** Name of this input for "Other" tag */
382 public String format
;
385 * Default (empty) constructor
400 public InputData(String name
, int action
, String format
) {
402 this.action
= action
;
403 this.format
= format
;
407 * Constructor with default format
414 public InputData(String name
, int action
) {
416 this.action
= action
;
428 public InputData(Tag tag
, int action
) {
430 this.action
= action
;
435 * Input line cardinality
437 public static class Cardinality
{
439 /** Representation of infinity */
440 public static final int INF
= Integer
.MAX_VALUE
;
442 /** Preset for [1, 1] */
443 public static final Cardinality ONE
= new Cardinality(1, 1);
445 /** Preset for [1, inf] */
446 public static final Cardinality ONE_OR_MORE
= new Cardinality(1, INF
);
448 /** Preset for [0, 1] */
449 public static final Cardinality ZERO_OR_ONE
= new Cardinality(0, 1);
451 /** Preset for [0, inf] */
452 public static final Cardinality ZERO_OR_MORE
= new Cardinality(0, INF
);
454 private final int min
;
455 private final int max
;
465 public Cardinality(int min
, int max
) {
471 public String
toString() {
472 return "(" + (min
>= 0 ? min
: "?") + ',' + (max
== INF ?
"\u221E" : (max
>= 0 ? max
: "?")) + ')'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
476 public int hashCode() {
477 final int prime
= 31;
479 result
= prime
* result
+ max
;
480 result
= prime
* result
+ min
;
485 public boolean equals(Object obj
) {
492 if (!(obj
instanceof Cardinality
)) {
495 Cardinality other
= (Cardinality
) obj
;
496 return (this.min
== other
.min
&& this.max
== other
.max
);
502 save(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
506 public void save(String path
) {
508 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
509 DocumentBuilder db
= dbf
.newDocumentBuilder();
511 // The following allows xml parsing without access to the dtd
512 db
.setEntityResolver(createEmptyEntityResolver());
514 // The following catches xml parsing exceptions
515 db
.setErrorHandler(createErrorHandler());
518 File file
= new File(path
);
519 if (file
.canRead()) {
520 doc
= db
.parse(file
);
521 if (!doc
.getDocumentElement().getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
522 Activator
.logError(String
.format("Error saving CustomTxtTraceDefinition: path=%s is not a valid custom parser file", path
)); //$NON-NLS-1$
526 doc
= db
.newDocument();
527 Node node
= doc
.createElement(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
);
528 doc
.appendChild(node
);
531 Element root
= doc
.getDocumentElement();
533 Element oldDefinitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
534 if (oldDefinitionElement
!= null) {
535 root
.removeChild(oldDefinitionElement
);
537 Element definitionElement
= doc
.createElement(DEFINITION_ELEMENT
);
538 root
.appendChild(definitionElement
);
539 definitionElement
.setAttribute(CATEGORY_ATTRIBUTE
, categoryName
);
540 definitionElement
.setAttribute(NAME_ATTRIBUTE
, definitionName
);
542 if (timeStampOutputFormat
!= null && !timeStampOutputFormat
.isEmpty()) {
543 Element formatElement
= doc
.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
);
544 definitionElement
.appendChild(formatElement
);
545 formatElement
.appendChild(doc
.createTextNode(timeStampOutputFormat
));
548 if (inputs
!= null) {
549 for (InputLine inputLine
: inputs
) {
550 definitionElement
.appendChild(createInputLineElement(inputLine
, doc
));
554 if (outputs
!= null) {
555 for (OutputColumn output
: outputs
) {
556 Element outputColumnElement
= doc
.createElement(OUTPUT_COLUMN_ELEMENT
);
557 definitionElement
.appendChild(outputColumnElement
);
558 outputColumnElement
.setAttribute(TAG_ATTRIBUTE
, output
.tag
.name());
559 outputColumnElement
.setAttribute(NAME_ATTRIBUTE
, output
.name
);
563 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
564 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
566 // initialize StreamResult with File object to save to file
567 StreamResult result
= new StreamResult(new StringWriter());
568 DOMSource source
= new DOMSource(doc
);
569 transformer
.transform(source
, result
);
570 String xmlString
= result
.getWriter().toString();
572 try (FileWriter writer
= new FileWriter(file
);) {
573 writer
.write(xmlString
);
576 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
578 } catch (ParserConfigurationException
| TransformerFactoryConfigurationError
| TransformerException
| IOException
| SAXException e
) {
579 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
583 private Element
createInputLineElement(InputLine inputLine
, Document doc
) {
584 Element inputLineElement
= doc
.createElement(INPUT_LINE_ELEMENT
);
586 Element cardinalityElement
= doc
.createElement(CARDINALITY_ELEMENT
);
587 inputLineElement
.appendChild(cardinalityElement
);
588 cardinalityElement
.setAttribute(MIN_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.min
));
589 cardinalityElement
.setAttribute(MAX_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.max
));
591 Element regexElement
= doc
.createElement(REGEX_ELEMENT
);
592 inputLineElement
.appendChild(regexElement
);
593 regexElement
.appendChild(doc
.createTextNode(inputLine
.regex
));
595 if (inputLine
.eventType
!= null) {
596 Element eventTypeElement
= doc
.createElement(EVENT_TYPE_ELEMENT
);
597 inputLineElement
.appendChild(eventTypeElement
);
598 eventTypeElement
.appendChild(doc
.createTextNode(inputLine
.eventType
));
601 if (inputLine
.columns
!= null) {
602 for (InputData inputData
: inputLine
.columns
) {
603 Element inputDataElement
= doc
.createElement(INPUT_DATA_ELEMENT
);
604 inputLineElement
.appendChild(inputDataElement
);
605 inputDataElement
.setAttribute(TAG_ATTRIBUTE
, inputData
.tag
.name());
606 inputDataElement
.setAttribute(NAME_ATTRIBUTE
, inputData
.name
);
607 inputDataElement
.setAttribute(ACTION_ATTRIBUTE
, Integer
.toString(inputData
.action
));
608 if (inputData
.format
!= null) {
609 inputDataElement
.setAttribute(FORMAT_ATTRIBUTE
, inputData
.format
);
614 if (inputLine
.childrenInputs
!= null) {
615 for (InputLine childInputLine
: inputLine
.childrenInputs
) {
616 inputLineElement
.appendChild(createInputLineElement(childInputLine
, doc
));
620 return inputLineElement
;
624 * Load all custom text trace definitions, including the user-defined and
625 * default (built-in) parsers.
627 * @return The loaded trace definitions
629 public static CustomTxtTraceDefinition
[] loadAll() {
630 return loadAll(true);
634 * Load all custom text trace definitions, including the user-defined and,
635 * optionally, the default (built-in) parsers.
637 * @param includeDefaults
638 * if true, the default (built-in) parsers are included
640 * @return The loaded trace definitions
642 public static CustomTxtTraceDefinition
[] loadAll(boolean includeDefaults
) {
643 File defaultFile
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
644 File legacyFileCore
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
645 File legacyFileUI
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
648 * If there is no file at the expected location, check the legacy
651 if (!defaultFile
.exists()) {
652 if (legacyFileCore
.exists()) {
653 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
654 } else if (legacyFileUI
.exists()) {
655 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
659 Set
<CustomTxtTraceDefinition
> defs
= new TreeSet
<>(new Comparator
<CustomTxtTraceDefinition
>() {
661 public int compare(CustomTxtTraceDefinition o1
, CustomTxtTraceDefinition o2
) {
662 int result
= o1
.categoryName
.compareTo(o2
.categoryName
);
666 return o1
.definitionName
.compareTo(o2
.definitionName
);
669 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
)));
670 if (includeDefaults
) {
671 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
)));
673 return defs
.toArray(new CustomTxtTraceDefinition
[0]);
677 private static void transferDefinitions(String defFile
) {
678 CustomTxtTraceDefinition
[] oldDefs
= loadAll(defFile
);
679 for (CustomTxtTraceDefinition def
: oldDefs
) {
680 /* Save in the new location */
686 * Load a specific text trace definition file.
689 * The path to the file to load
690 * @return The loaded trace definitions
692 public static CustomTxtTraceDefinition
[] loadAll(String path
) {
694 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
695 DocumentBuilder db
= dbf
.newDocumentBuilder();
697 // The following allows xml parsing without access to the dtd
698 db
.setEntityResolver(createEmptyEntityResolver());
700 // The following catches xml parsing exceptions
701 db
.setErrorHandler(createErrorHandler());
703 File file
= new File(path
);
704 if (!file
.canRead()) {
705 return new CustomTxtTraceDefinition
[0];
707 Document doc
= db
.parse(file
);
709 Element root
= doc
.getDocumentElement();
710 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
711 return new CustomTxtTraceDefinition
[0];
714 ArrayList
<CustomTxtTraceDefinition
> defList
= new ArrayList
<>();
715 NodeList nodeList
= root
.getChildNodes();
716 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
717 Node node
= nodeList
.item(i
);
718 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
719 CustomTxtTraceDefinition def
= extractDefinition((Element
) node
);
725 return defList
.toArray(new CustomTxtTraceDefinition
[0]);
726 } catch (ParserConfigurationException e
) {
727 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
728 } catch (SAXException e
) {
729 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
730 } catch (IOException e
) {
731 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
733 return new CustomTxtTraceDefinition
[0];
737 * Load a single definition.
739 * @param categoryName
740 * Category of the definition to load
741 * @param definitionName
742 * Name of the definition to load
743 * @return The loaded trace definition
745 public static CustomTxtTraceDefinition
load(String categoryName
, String definitionName
) {
747 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
748 DocumentBuilder db
= dbf
.newDocumentBuilder();
750 // The following allows xml parsing without access to the dtd
751 db
.setEntityResolver(createEmptyEntityResolver());
753 // The following catches xml parsing exceptions
754 db
.setErrorHandler(createErrorHandler());
756 CustomTxtTraceDefinition value
= lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
758 return lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
);
761 } catch (ParserConfigurationException
| SAXException
| IOException e
) {
762 Activator
.logError("Error loading CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$
767 private static CustomTxtTraceDefinition
lookupDefinition(String categoryName
, String definitionName
, DocumentBuilder db
, String source
) throws SAXException
, IOException
{
768 File file
= new File(source
);
769 if (!file
.exists()) {
772 Document doc
= db
.parse(file
);
774 Element root
= doc
.getDocumentElement();
775 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
779 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
780 if (definitionElement
!= null) {
781 return extractDefinition(definitionElement
);
786 private static Element
findDefinitionElement(Element root
, String categoryName
, String definitionName
) {
787 NodeList nodeList
= root
.getChildNodes();
788 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
789 Node node
= nodeList
.item(i
);
790 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
791 Element element
= (Element
) node
;
792 String categoryAttribute
= element
.getAttribute(CATEGORY_ATTRIBUTE
);
793 if (categoryAttribute
.isEmpty()) {
794 categoryAttribute
= CUSTOM_TXT_CATEGORY
;
796 String nameAttribute
= element
.getAttribute(NAME_ATTRIBUTE
);
797 if (categoryName
.equals(categoryAttribute
) &&
798 definitionName
.equals(nameAttribute
)) {
807 * Get the definition from a definition element.
809 * @param definitionElement
810 * The Element to extract from
811 * @return The loaded trace definition
813 public static CustomTxtTraceDefinition
extractDefinition(Element definitionElement
) {
814 CustomTxtTraceDefinition def
= new CustomTxtTraceDefinition();
816 def
.categoryName
= definitionElement
.getAttribute(CATEGORY_ATTRIBUTE
);
817 if (def
.categoryName
.isEmpty()) {
818 def
.categoryName
= CUSTOM_TXT_CATEGORY
;
820 def
.definitionName
= definitionElement
.getAttribute(NAME_ATTRIBUTE
);
821 if (def
.definitionName
.isEmpty()) {
825 NodeList nodeList
= definitionElement
.getChildNodes();
826 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
827 Node node
= nodeList
.item(i
);
828 String nodeName
= node
.getNodeName();
829 if (nodeName
.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
)) {
830 Element formatElement
= (Element
) node
;
831 def
.timeStampOutputFormat
= formatElement
.getTextContent();
832 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
833 InputLine inputLine
= extractInputLine((Element
) node
);
834 if (inputLine
!= null) {
835 def
.inputs
.add(inputLine
);
837 } else if (nodeName
.equals(OUTPUT_COLUMN_ELEMENT
)) {
838 Element outputColumnElement
= (Element
) node
;
839 Entry
<@NonNull Tag
, @NonNull String
> entry
= extractTagAndName(outputColumnElement
, TAG_ATTRIBUTE
, NAME_ATTRIBUTE
);
840 OutputColumn outputColumn
= new OutputColumn(entry
.getKey(), entry
.getValue());
841 def
.outputs
.add(outputColumn
);
847 private static InputLine
extractInputLine(Element inputLineElement
) {
848 InputLine inputLine
= new InputLine();
849 NodeList nodeList
= inputLineElement
.getChildNodes();
850 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
851 Node node
= nodeList
.item(i
);
852 String nodeName
= node
.getNodeName();
853 if (nodeName
.equals(CARDINALITY_ELEMENT
)) {
854 Element cardinalityElement
= (Element
) node
;
856 int min
= Integer
.parseInt(cardinalityElement
.getAttribute(MIN_ATTRIBUTE
));
857 int max
= Integer
.parseInt(cardinalityElement
.getAttribute(MAX_ATTRIBUTE
));
858 inputLine
.cardinality
= new Cardinality(min
, max
);
859 } catch (NumberFormatException e
) {
862 } else if (nodeName
.equals(REGEX_ELEMENT
)) {
863 Element regexElement
= (Element
) node
;
864 inputLine
.regex
= regexElement
.getTextContent();
865 } else if (nodeName
.equals(EVENT_TYPE_ELEMENT
)) {
866 Element eventTypeElement
= (Element
) node
;
867 inputLine
.eventType
= eventTypeElement
.getTextContent();
868 } else if (nodeName
.equals(INPUT_DATA_ELEMENT
)) {
869 Element inputDataElement
= (Element
) node
;
870 InputData inputData
= new InputData();
871 Entry
<@NonNull Tag
, @NonNull String
> entry
= extractTagAndName(inputDataElement
, TAG_ATTRIBUTE
, NAME_ATTRIBUTE
);
872 inputData
.tag
= checkNotNull(entry
.getKey());
873 inputData
.name
= checkNotNull(entry
.getValue());
874 inputData
.action
= Integer
.parseInt(inputDataElement
.getAttribute(ACTION_ATTRIBUTE
));
875 inputData
.format
= inputDataElement
.getAttribute(FORMAT_ATTRIBUTE
);
876 inputLine
.addColumn(inputData
);
877 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
878 Element childInputLineElement
= (Element
) node
;
879 InputLine childInputLine
= extractInputLine(childInputLineElement
);
880 if (childInputLine
!= null) {
881 inputLine
.addChild(childInputLine
);
889 * Delete a definition from the currently loaded ones.
891 * @param categoryName
892 * The category of the definition to delete
893 * @param definitionName
894 * The name of the definition to delete
896 public static void delete(String categoryName
, String definitionName
) {
898 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
899 DocumentBuilder db
= dbf
.newDocumentBuilder();
901 // The following allows xml parsing without access to the dtd
902 db
.setEntityResolver(createEmptyEntityResolver());
904 // The following catches xml parsing exceptions
905 db
.setErrorHandler(createErrorHandler());
907 File file
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
908 Document doc
= db
.parse(file
);
910 Element root
= doc
.getDocumentElement();
911 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
915 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
916 if (definitionElement
!= null) {
917 root
.removeChild(definitionElement
);
920 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
921 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
923 // initialize StreamResult with File object to save to file
924 StreamResult result
= new StreamResult(new StringWriter());
925 DOMSource source
= new DOMSource(doc
);
926 transformer
.transform(source
, result
);
927 String xmlString
= result
.getWriter().toString();
929 try (FileWriter writer
= new FileWriter(file
);) {
930 writer
.write(xmlString
);
933 TmfTraceType
.removeCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
934 // Check if default definition needs to be reloaded
935 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
937 } catch (ParserConfigurationException
| SAXException
| IOException
| TransformerFactoryConfigurationError
| TransformerException e
) {
938 Activator
.logError("Error deleting CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$