1 /*******************************************************************************
2 * Copyright (c) 2010, 2015 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
;
17 import java
.io
.FileWriter
;
18 import java
.io
.IOException
;
19 import java
.io
.StringWriter
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Arrays
;
22 import java
.util
.Comparator
;
23 import java
.util
.List
;
26 import java
.util
.TreeSet
;
27 import java
.util
.regex
.Pattern
;
28 import java
.util
.regex
.PatternSyntaxException
;
30 import javax
.xml
.parsers
.DocumentBuilder
;
31 import javax
.xml
.parsers
.DocumentBuilderFactory
;
32 import javax
.xml
.parsers
.ParserConfigurationException
;
33 import javax
.xml
.transform
.OutputKeys
;
34 import javax
.xml
.transform
.Transformer
;
35 import javax
.xml
.transform
.TransformerConfigurationException
;
36 import javax
.xml
.transform
.TransformerException
;
37 import javax
.xml
.transform
.TransformerFactory
;
38 import javax
.xml
.transform
.TransformerFactoryConfigurationError
;
39 import javax
.xml
.transform
.dom
.DOMSource
;
40 import javax
.xml
.transform
.stream
.StreamResult
;
42 import org
.eclipse
.core
.runtime
.Platform
;
43 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
45 import org
.w3c
.dom
.Document
;
46 import org
.w3c
.dom
.Element
;
47 import org
.w3c
.dom
.Node
;
48 import org
.w3c
.dom
.NodeList
;
49 import org
.xml
.sax
.SAXException
;
52 * Trace definition for custom text traces.
54 * @author Patrick Tassé
56 public class CustomTxtTraceDefinition
extends CustomTraceDefinition
{
59 public List
<InputLine
> inputs
;
62 * Custom text label used internally and therefore should not be
65 public static final String CUSTOM_TXT_CATEGORY
= "Custom Text"; //$NON-NLS-1$
68 /** File name of the default definition file */
69 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
= "custom_txt_default_parsers.xml"; //$NON-NLS-1$
70 /** File name of the definition file */
71 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
= "custom_txt_parsers.xml"; //$NON-NLS-1$
73 /** Path of the definition file */
74 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
=
75 Platform
.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
76 CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
;
77 /** Path of the definition file */
78 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
=
79 Activator
.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
82 * Legacy path to the XML definitions file (in the UI plug-in of linuxtools) TODO Remove
83 * once we feel the transition phase is over.
85 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
=
86 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
87 .append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
88 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
91 * Legacy path to the XML definitions file (in the core plug-in of linuxtools) TODO Remove
92 * once we feel the transition phase is over.
94 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
=
95 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
96 .append("org.eclipse.linuxtools.tmf.core") //$NON-NLS-1$
97 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
99 private static final String CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
= Messages
.CustomTxtTraceDefinition_definitionRootElement
;
100 private static final String DEFINITION_ELEMENT
= Messages
.CustomTxtTraceDefinition_definition
;
101 private static final String CATEGORY_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_category
;
102 private static final String NAME_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_name
;
103 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT
= Messages
.CustomTxtTraceDefinition_timestampOutputFormat
;
104 private static final String INPUT_LINE_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputLine
;
105 private static final String CARDINALITY_ELEMENT
= Messages
.CustomTxtTraceDefinition_cardinality
;
106 private static final String MIN_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_min
;
107 private static final String MAX_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_max
;
108 private static final String REGEX_ELEMENT
= Messages
.CustomTxtTraceDefinition_regEx
;
109 private static final String INPUT_DATA_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputData
;
110 private static final String ACTION_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_action
;
111 private static final String FORMAT_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_format
;
112 private static final String OUTPUT_COLUMN_ELEMENT
= Messages
.CustomTxtTraceDefinition_outputColumn
;
115 * Default constructor.
117 public CustomTxtTraceDefinition() {
118 this(CUSTOM_TXT_CATEGORY
, "", new ArrayList
<InputLine
>(0), new ArrayList
<OutputColumn
>(0), ""); //$NON-NLS-1$ //$NON-NLS-2$
125 * Category of the trace type
127 * Name of the trace type
131 * List of output columns
132 * @param timeStampOutputFormat
133 * The timestamp format to use
135 public CustomTxtTraceDefinition(String category
, String traceType
, List
<InputLine
> inputs
,
136 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
137 this.categoryName
= category
;
138 this.definitionName
= traceType
;
139 this.inputs
= inputs
;
140 this.outputs
= outputs
;
141 this.timeStampOutputFormat
= timeStampOutputFormat
;
145 * Wrapper to store a line of the log file
147 public static class InputLine
{
149 /** Data columns of this line */
150 public List
<InputData
> columns
;
152 /** Cardinality of this line (see {@link Cardinality}) */
153 public Cardinality cardinality
;
156 public InputLine parentInput
;
158 /** Level of this line */
161 /** Next input line in the file */
162 public InputLine nextInput
;
164 /** Children of this line (if one "event" spans many lines) */
165 public List
<InputLine
> childrenInputs
;
167 private String regex
;
168 private Pattern pattern
;
171 * Default (empty) constructor.
180 * Cardinality of this line.
186 public InputLine(Cardinality cardinality
, String regex
, List
<InputData
> columns
) {
187 this.cardinality
= cardinality
;
189 this.columns
= columns
;
193 * Set the regex of this input line
198 public void setRegex(String regex
) {
204 * Get the current regex
206 * @return The current regex
208 public String
getRegex() {
213 * Get the Pattern object of this line's regex
215 * @return The Pattern
216 * @throws PatternSyntaxException
217 * If the regex does not parse correctly
219 public Pattern
getPattern() throws PatternSyntaxException
{
220 if (pattern
== null) {
221 pattern
= Pattern
.compile(regex
);
227 * Add a child line to this line.
230 * The child input line
232 public void addChild(InputLine input
) {
233 if (childrenInputs
== null) {
234 childrenInputs
= new ArrayList
<>(1);
235 } else if (childrenInputs
.size() > 0) {
236 InputLine last
= childrenInputs
.get(childrenInputs
.size() - 1);
237 last
.nextInput
= input
;
239 childrenInputs
.add(input
);
240 input
.parentInput
= this;
241 input
.level
= this.level
+ 1;
245 * Set the next input line.
248 * The next input line
250 public void addNext(InputLine input
) {
251 if (parentInput
!= null) {
252 int index
= parentInput
.childrenInputs
.indexOf(this);
253 parentInput
.childrenInputs
.add(index
+ 1, input
);
254 InputLine next
= nextInput
;
256 input
.nextInput
= next
;
258 input
.parentInput
= this.parentInput
;
259 input
.level
= this.level
;
263 * Move this line up in its parent's children.
265 public void moveUp() {
266 if (parentInput
!= null) {
267 int index
= parentInput
.childrenInputs
.indexOf(this);
269 parentInput
.childrenInputs
.add(index
- 1, parentInput
.childrenInputs
.remove(index
));
270 parentInput
.childrenInputs
.get(index
).nextInput
= nextInput
;
271 nextInput
= parentInput
.childrenInputs
.get(index
);
277 * Move this line down in its parent's children.
279 public void moveDown() {
280 if (parentInput
!= null) {
281 int index
= parentInput
.childrenInputs
.indexOf(this);
282 if (index
< parentInput
.childrenInputs
.size() - 1) {
283 parentInput
.childrenInputs
.add(index
+ 1, parentInput
.childrenInputs
.remove(index
));
284 nextInput
= parentInput
.childrenInputs
.get(index
).nextInput
;
285 parentInput
.childrenInputs
.get(index
).nextInput
= this;
291 * Add a data column to this line
296 public void addColumn(InputData column
) {
297 if (columns
== null) {
298 columns
= new ArrayList
<>(1);
304 * Get the next input lines.
307 * The map of line "sets".
308 * @return The next list of lines.
310 public List
<InputLine
> getNextInputs(Map
<InputLine
, Integer
> countMap
) {
311 List
<InputLine
> nextInputs
= new ArrayList
<>();
312 InputLine next
= nextInput
;
313 while (next
!= null) {
314 nextInputs
.add(next
);
315 if (next
.cardinality
.min
> 0) {
318 next
= next
.nextInput
;
320 if (parentInput
!= null && parentInput
.level
> 0) {
321 int parentCount
= countMap
.get(parentInput
);
322 if (parentCount
< parentInput
.getMaxCount()) {
323 nextInputs
.add(parentInput
);
325 if (parentCount
< parentInput
.getMinCount()) {
328 nextInputs
.addAll(parentInput
.getNextInputs(countMap
));
334 * Get the minimum possible amount of entries.
336 * @return The minimum
338 public int getMinCount() {
339 return cardinality
.min
;
343 * Get the maximum possible amount of entries.
345 * @return The maximum
347 public int getMaxCount() {
348 return cardinality
.max
;
352 public String
toString() {
353 return regex
+ " " + cardinality
; //$NON-NLS-1$
358 * Data column for input lines.
360 public static class InputData
{
362 /** Name of this column */
369 public String format
;
372 * Default (empty) constructor
387 public InputData(String name
, int action
, String format
) {
389 this.action
= action
;
390 this.format
= format
;
394 * Constructor with default format
401 public InputData(String name
, int action
) {
403 this.action
= action
;
408 * Input line cardinality
410 public static class Cardinality
{
412 /** Representation of infinity */
413 public final static int INF
= Integer
.MAX_VALUE
;
415 /** Preset for [1, 1] */
416 public final static Cardinality ONE
= new Cardinality(1, 1);
418 /** Preset for [1, inf] */
419 public final static Cardinality ONE_OR_MORE
= new Cardinality(1, INF
);
421 /** Preset for [0, 1] */
422 public final static Cardinality ZERO_OR_ONE
= new Cardinality(0, 1);
424 /** Preset for [0, inf] */
425 public final static Cardinality ZERO_OR_MORE
= new Cardinality(0, INF
);
427 private final int min
;
428 private final int max
;
438 public Cardinality(int min
, int max
) {
444 public String
toString() {
445 return "(" + (min
>= 0 ? min
: "?") + ',' + (max
== INF ?
"\u221E" : (max
>= 0 ? max
: "?")) + ')'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
449 public int hashCode() {
450 final int prime
= 31;
452 result
= prime
* result
+ max
;
453 result
= prime
* result
+ min
;
458 public boolean equals(Object obj
) {
465 if (!(obj
instanceof Cardinality
)) {
468 Cardinality other
= (Cardinality
) obj
;
469 return (this.min
== other
.min
&& this.max
== other
.max
);
475 save(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
479 public void save(String path
) {
481 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
482 DocumentBuilder db
= dbf
.newDocumentBuilder();
484 // The following allows xml parsing without access to the dtd
485 db
.setEntityResolver(createEmptyEntityResolver());
487 // The following catches xml parsing exceptions
488 db
.setErrorHandler(createErrorHandler());
491 File file
= new File(path
);
492 if (file
.canRead()) {
493 doc
= db
.parse(file
);
494 if (!doc
.getDocumentElement().getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
498 doc
= db
.newDocument();
499 Node node
= doc
.createElement(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
);
500 doc
.appendChild(node
);
503 Element root
= doc
.getDocumentElement();
505 Element oldDefinitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
506 if (oldDefinitionElement
!= null) {
507 root
.removeChild(oldDefinitionElement
);
509 Element definitionElement
= doc
.createElement(DEFINITION_ELEMENT
);
510 root
.appendChild(definitionElement
);
511 definitionElement
.setAttribute(CATEGORY_ATTRIBUTE
, categoryName
);
512 definitionElement
.setAttribute(NAME_ATTRIBUTE
, definitionName
);
514 Element formatElement
= doc
.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
);
515 definitionElement
.appendChild(formatElement
);
516 formatElement
.appendChild(doc
.createTextNode(timeStampOutputFormat
));
518 if (inputs
!= null) {
519 for (InputLine inputLine
: inputs
) {
520 definitionElement
.appendChild(createInputLineElement(inputLine
, doc
));
524 if (outputs
!= null) {
525 for (OutputColumn output
: outputs
) {
526 Element outputColumnElement
= doc
.createElement(OUTPUT_COLUMN_ELEMENT
);
527 definitionElement
.appendChild(outputColumnElement
);
528 outputColumnElement
.setAttribute(NAME_ATTRIBUTE
, output
.name
);
532 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
533 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
535 // initialize StreamResult with File object to save to file
536 StreamResult result
= new StreamResult(new StringWriter());
537 DOMSource source
= new DOMSource(doc
);
538 transformer
.transform(source
, result
);
539 String xmlString
= result
.getWriter().toString();
541 try (FileWriter writer
= new FileWriter(file
);) {
542 writer
.write(xmlString
);
545 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
547 } catch (ParserConfigurationException e
) {
548 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
549 } catch (TransformerConfigurationException e
) {
550 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
551 } catch (TransformerFactoryConfigurationError e
) {
552 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
553 } catch (TransformerException e
) {
554 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
555 } catch (IOException e
) {
556 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
557 } catch (SAXException e
) {
558 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
562 private Element
createInputLineElement(InputLine inputLine
, Document doc
) {
563 Element inputLineElement
= doc
.createElement(INPUT_LINE_ELEMENT
);
565 Element cardinalityElement
= doc
.createElement(CARDINALITY_ELEMENT
);
566 inputLineElement
.appendChild(cardinalityElement
);
567 cardinalityElement
.setAttribute(MIN_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.min
));
568 cardinalityElement
.setAttribute(MAX_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.max
));
570 Element regexElement
= doc
.createElement(REGEX_ELEMENT
);
571 inputLineElement
.appendChild(regexElement
);
572 regexElement
.appendChild(doc
.createTextNode(inputLine
.regex
));
574 if (inputLine
.columns
!= null) {
575 for (InputData inputData
: inputLine
.columns
) {
576 Element inputDataElement
= doc
.createElement(INPUT_DATA_ELEMENT
);
577 inputLineElement
.appendChild(inputDataElement
);
578 inputDataElement
.setAttribute(NAME_ATTRIBUTE
, inputData
.name
);
579 inputDataElement
.setAttribute(ACTION_ATTRIBUTE
, Integer
.toString(inputData
.action
));
580 if (inputData
.format
!= null) {
581 inputDataElement
.setAttribute(FORMAT_ATTRIBUTE
, inputData
.format
);
586 if (inputLine
.childrenInputs
!= null) {
587 for (InputLine childInputLine
: inputLine
.childrenInputs
) {
588 inputLineElement
.appendChild(createInputLineElement(childInputLine
, doc
));
592 return inputLineElement
;
596 * Load all custom text trace definitions, including the user-defined and
597 * default (built-in) parsers.
599 * @return The loaded trace definitions
601 public static CustomTxtTraceDefinition
[] loadAll() {
602 return loadAll(true);
606 * Load all custom text trace definitions, including the user-defined and,
607 * optionally, the default (built-in) parsers.
609 * @param includeDefaults
610 * if true, the default (built-in) parsers are included
612 * @return The loaded trace definitions
614 public static CustomTxtTraceDefinition
[] loadAll(boolean includeDefaults
) {
615 File defaultFile
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
616 File legacyFileCore
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
617 File legacyFileUI
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
620 * If there is no file at the expected location, check the legacy
623 if (!defaultFile
.exists()) {
624 if (legacyFileCore
.exists()) {
625 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
626 } else if (legacyFileUI
.exists()) {
627 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
631 Set
<CustomTxtTraceDefinition
> defs
= new TreeSet
<>(new Comparator
<CustomTxtTraceDefinition
>() {
633 public int compare(CustomTxtTraceDefinition o1
, CustomTxtTraceDefinition o2
) {
634 int result
= o1
.categoryName
.compareTo(o2
.categoryName
);
638 return o1
.definitionName
.compareTo(o2
.definitionName
);
641 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
)));
642 if (includeDefaults
) {
643 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
)));
645 return defs
.toArray(new CustomTxtTraceDefinition
[0]);
649 private static void transferDefinitions(String defFile
) {
650 CustomTxtTraceDefinition
[] oldDefs
= loadAll(defFile
);
651 for (CustomTxtTraceDefinition def
: oldDefs
) {
652 /* Save in the new location */
658 * Load a specific text trace definition file.
661 * The path to the file to load
662 * @return The loaded trace definitions
664 public static CustomTxtTraceDefinition
[] loadAll(String path
) {
666 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
667 DocumentBuilder db
= dbf
.newDocumentBuilder();
669 // The following allows xml parsing without access to the dtd
670 db
.setEntityResolver(createEmptyEntityResolver());
672 // The following catches xml parsing exceptions
673 db
.setErrorHandler(createErrorHandler());
675 File file
= new File(path
);
676 if (!file
.canRead()) {
677 return new CustomTxtTraceDefinition
[0];
679 Document doc
= db
.parse(file
);
681 Element root
= doc
.getDocumentElement();
682 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
683 return new CustomTxtTraceDefinition
[0];
686 ArrayList
<CustomTxtTraceDefinition
> defList
= new ArrayList
<>();
687 NodeList nodeList
= root
.getChildNodes();
688 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
689 Node node
= nodeList
.item(i
);
690 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
691 CustomTxtTraceDefinition def
= extractDefinition((Element
) node
);
697 return defList
.toArray(new CustomTxtTraceDefinition
[0]);
698 } catch (ParserConfigurationException e
) {
699 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
700 } catch (SAXException e
) {
701 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
702 } catch (IOException e
) {
703 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
705 return new CustomTxtTraceDefinition
[0];
709 * Load a single definition.
711 * @param categoryName
712 * Category of the definition to load
713 * @param definitionName
714 * Name of the definition to load
715 * @return The loaded trace definition
717 public static CustomTxtTraceDefinition
load(String categoryName
, String definitionName
) {
719 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
720 DocumentBuilder db
= dbf
.newDocumentBuilder();
722 // The following allows xml parsing without access to the dtd
723 db
.setEntityResolver(createEmptyEntityResolver());
725 // The following catches xml parsing exceptions
726 db
.setErrorHandler(createErrorHandler());
728 CustomTxtTraceDefinition value
= lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
730 return lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
);
733 } catch (ParserConfigurationException
| SAXException
| IOException e
) {
734 Activator
.logError("Error loading CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$
739 private static CustomTxtTraceDefinition
lookupDefinition(String categoryName
, String definitionName
, DocumentBuilder db
, String source
) throws SAXException
, IOException
{
740 File file
= new File(source
);
741 if (!file
.exists()) {
744 Document doc
= db
.parse(file
);
746 Element root
= doc
.getDocumentElement();
747 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
751 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
752 if (definitionElement
!= null) {
753 return extractDefinition(definitionElement
);
758 private static Element
findDefinitionElement(Element root
, String categoryName
, String definitionName
) {
759 NodeList nodeList
= root
.getChildNodes();
760 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
761 Node node
= nodeList
.item(i
);
762 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
763 Element element
= (Element
) node
;
764 String categoryAttribute
= element
.getAttribute(CATEGORY_ATTRIBUTE
);
765 if (categoryAttribute
.isEmpty()) {
766 categoryAttribute
= CUSTOM_TXT_CATEGORY
;
768 String nameAttribute
= element
.getAttribute(NAME_ATTRIBUTE
);
769 if (categoryName
.equals(categoryAttribute
) &&
770 definitionName
.equals(nameAttribute
)) {
779 * Get the definition from a definition element.
781 * @param definitionElement
782 * The Element to extract from
783 * @return The loaded trace definition
785 public static CustomTxtTraceDefinition
extractDefinition(Element definitionElement
) {
786 CustomTxtTraceDefinition def
= new CustomTxtTraceDefinition();
788 def
.categoryName
= definitionElement
.getAttribute(CATEGORY_ATTRIBUTE
);
789 if (def
.categoryName
.isEmpty()) {
790 def
.categoryName
= CUSTOM_TXT_CATEGORY
;
792 def
.definitionName
= definitionElement
.getAttribute(NAME_ATTRIBUTE
);
793 if (def
.definitionName
.isEmpty()) {
797 NodeList nodeList
= definitionElement
.getChildNodes();
798 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
799 Node node
= nodeList
.item(i
);
800 String nodeName
= node
.getNodeName();
801 if (nodeName
.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
)) {
802 Element formatElement
= (Element
) node
;
803 def
.timeStampOutputFormat
= formatElement
.getTextContent();
804 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
805 InputLine inputLine
= extractInputLine((Element
) node
);
806 if (inputLine
!= null) {
807 def
.inputs
.add(inputLine
);
809 } else if (nodeName
.equals(OUTPUT_COLUMN_ELEMENT
)) {
810 Element outputColumnElement
= (Element
) node
;
811 OutputColumn outputColumn
= new OutputColumn();
812 outputColumn
.name
= outputColumnElement
.getAttribute(NAME_ATTRIBUTE
);
813 def
.outputs
.add(outputColumn
);
819 private static InputLine
extractInputLine(Element inputLineElement
) {
820 InputLine inputLine
= new InputLine();
821 NodeList nodeList
= inputLineElement
.getChildNodes();
822 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
823 Node node
= nodeList
.item(i
);
824 String nodeName
= node
.getNodeName();
825 if (nodeName
.equals(CARDINALITY_ELEMENT
)) {
826 Element cardinalityElement
= (Element
) node
;
828 int min
= Integer
.parseInt(cardinalityElement
.getAttribute(MIN_ATTRIBUTE
));
829 int max
= Integer
.parseInt(cardinalityElement
.getAttribute(MAX_ATTRIBUTE
));
830 inputLine
.cardinality
= new Cardinality(min
, max
);
831 } catch (NumberFormatException e
) {
834 } else if (nodeName
.equals(REGEX_ELEMENT
)) {
835 Element regexElement
= (Element
) node
;
836 inputLine
.regex
= regexElement
.getTextContent();
837 } else if (nodeName
.equals(INPUT_DATA_ELEMENT
)) {
838 Element inputDataElement
= (Element
) node
;
839 InputData inputData
= new InputData();
840 inputData
.name
= inputDataElement
.getAttribute(NAME_ATTRIBUTE
);
841 inputData
.action
= Integer
.parseInt(inputDataElement
.getAttribute(ACTION_ATTRIBUTE
));
842 inputData
.format
= inputDataElement
.getAttribute(FORMAT_ATTRIBUTE
);
843 inputLine
.addColumn(inputData
);
844 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
845 Element childInputLineElement
= (Element
) node
;
846 InputLine childInputLine
= extractInputLine(childInputLineElement
);
847 if (childInputLine
!= null) {
848 inputLine
.addChild(childInputLine
);
856 * Delete a definition from the currently loaded ones.
858 * @param categoryName
859 * The category of the definition to delete
860 * @param definitionName
861 * The name of the definition to delete
863 public static void delete(String categoryName
, String definitionName
) {
865 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
866 DocumentBuilder db
= dbf
.newDocumentBuilder();
868 // The following allows xml parsing without access to the dtd
869 db
.setEntityResolver(createEmptyEntityResolver());
871 // The following catches xml parsing exceptions
872 db
.setErrorHandler(createErrorHandler());
874 File file
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
875 Document doc
= db
.parse(file
);
877 Element root
= doc
.getDocumentElement();
878 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
882 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
883 if (definitionElement
!= null) {
884 root
.removeChild(definitionElement
);
887 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
888 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
890 // initialize StreamResult with File object to save to file
891 StreamResult result
= new StreamResult(new StringWriter());
892 DOMSource source
= new DOMSource(doc
);
893 transformer
.transform(source
, result
);
894 String xmlString
= result
.getWriter().toString();
896 try (FileWriter writer
= new FileWriter(file
);) {
897 writer
.write(xmlString
);
900 TmfTraceType
.removeCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
901 // Check if default definition needs to be reloaded
902 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
904 } catch (ParserConfigurationException
| SAXException
| IOException
| TransformerFactoryConfigurationError
| TransformerException e
) {
905 Activator
.logError("Error deleting CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$