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é
57 public class CustomTxtTraceDefinition
extends CustomTraceDefinition
{
60 public List
<InputLine
> inputs
;
63 * Custom text label used internally and therefore should not be
66 public static final String CUSTOM_TXT_CATEGORY
= "Custom Text"; //$NON-NLS-1$
69 /** File name of the default definition file */
70 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
= "custom_txt_default_parsers.xml"; //$NON-NLS-1$
71 /** File name of the definition file */
72 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
= "custom_txt_parsers.xml"; //$NON-NLS-1$
74 /** Path of the definition file */
75 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
=
76 Platform
.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
77 CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
;
78 /** Path of the definition file */
79 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
=
80 Activator
.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
83 * Legacy path to the XML definitions file (in the UI plug-in of linuxtools) TODO Remove
84 * once we feel the transition phase is over.
86 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
=
87 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
88 .append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
89 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
92 * Legacy path to the XML definitions file (in the core plug-in of linuxtools) TODO Remove
93 * once we feel the transition phase is over.
95 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
=
96 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
97 .append("org.eclipse.linuxtools.tmf.core") //$NON-NLS-1$
98 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
100 private static final String CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
= Messages
.CustomTxtTraceDefinition_definitionRootElement
;
101 private static final String DEFINITION_ELEMENT
= Messages
.CustomTxtTraceDefinition_definition
;
102 private static final String CATEGORY_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_category
;
103 private static final String NAME_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_name
;
104 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT
= Messages
.CustomTxtTraceDefinition_timestampOutputFormat
;
105 private static final String INPUT_LINE_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputLine
;
106 private static final String CARDINALITY_ELEMENT
= Messages
.CustomTxtTraceDefinition_cardinality
;
107 private static final String MIN_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_min
;
108 private static final String MAX_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_max
;
109 private static final String REGEX_ELEMENT
= Messages
.CustomTxtTraceDefinition_regEx
;
110 private static final String INPUT_DATA_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputData
;
111 private static final String ACTION_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_action
;
112 private static final String FORMAT_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_format
;
113 private static final String OUTPUT_COLUMN_ELEMENT
= Messages
.CustomTxtTraceDefinition_outputColumn
;
116 * Default constructor.
118 public CustomTxtTraceDefinition() {
119 this(CUSTOM_TXT_CATEGORY
, "", new ArrayList
<InputLine
>(0), new ArrayList
<OutputColumn
>(0), ""); //$NON-NLS-1$ //$NON-NLS-2$
126 * Name of the trace type
130 * List of output columns
131 * @param timeStampOutputFormat
132 * The timestamp format to use
133 * @deprecated Use {@link #CustomTxtTraceDefinition(String, String, List, List, String)}
136 public CustomTxtTraceDefinition(String traceType
, List
<InputLine
> inputs
,
137 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
138 this.definitionName
= traceType
;
139 this.inputs
= inputs
;
140 this.outputs
= outputs
;
141 this.timeStampOutputFormat
= timeStampOutputFormat
;
148 * Category of the trace type
150 * Name of the trace type
154 * List of output columns
155 * @param timeStampOutputFormat
156 * The timestamp format to use
159 public CustomTxtTraceDefinition(String category
, String traceType
, List
<InputLine
> inputs
,
160 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
161 this.categoryName
= category
;
162 this.definitionName
= traceType
;
163 this.inputs
= inputs
;
164 this.outputs
= outputs
;
165 this.timeStampOutputFormat
= timeStampOutputFormat
;
169 * Wrapper to store a line of the log file
171 public static class InputLine
{
173 /** Data columns of this line */
174 public List
<InputData
> columns
;
176 /** Cardinality of this line (see {@link Cardinality}) */
177 public Cardinality cardinality
;
180 public InputLine parentInput
;
182 /** Level of this line */
185 /** Next input line in the file */
186 public InputLine nextInput
;
188 /** Children of this line (if one "event" spans many lines) */
189 public List
<InputLine
> childrenInputs
;
191 private String regex
;
192 private Pattern pattern
;
195 * Default (empty) constructor.
204 * Cardinality of this line.
210 public InputLine(Cardinality cardinality
, String regex
, List
<InputData
> columns
) {
211 this.cardinality
= cardinality
;
213 this.columns
= columns
;
217 * Set the regex of this input line
222 public void setRegex(String regex
) {
228 * Get the current regex
230 * @return The current regex
232 public String
getRegex() {
237 * Get the Pattern object of this line's regex
239 * @return The Pattern
240 * @throws PatternSyntaxException
241 * If the regex does not parse correctly
243 public Pattern
getPattern() throws PatternSyntaxException
{
244 if (pattern
== null) {
245 pattern
= Pattern
.compile(regex
);
251 * Add a child line to this line.
254 * The child input line
256 public void addChild(InputLine input
) {
257 if (childrenInputs
== null) {
258 childrenInputs
= new ArrayList
<>(1);
259 } else if (childrenInputs
.size() > 0) {
260 InputLine last
= childrenInputs
.get(childrenInputs
.size() - 1);
261 last
.nextInput
= input
;
263 childrenInputs
.add(input
);
264 input
.parentInput
= this;
265 input
.level
= this.level
+ 1;
269 * Set the next input line.
272 * The next input line
274 public void addNext(InputLine input
) {
275 if (parentInput
!= null) {
276 int index
= parentInput
.childrenInputs
.indexOf(this);
277 parentInput
.childrenInputs
.add(index
+ 1, input
);
278 InputLine next
= nextInput
;
280 input
.nextInput
= next
;
282 input
.parentInput
= this.parentInput
;
283 input
.level
= this.level
;
287 * Move this line up in its parent's children.
289 public void moveUp() {
290 if (parentInput
!= null) {
291 int index
= parentInput
.childrenInputs
.indexOf(this);
293 parentInput
.childrenInputs
.add(index
- 1, parentInput
.childrenInputs
.remove(index
));
294 parentInput
.childrenInputs
.get(index
).nextInput
= nextInput
;
295 nextInput
= parentInput
.childrenInputs
.get(index
);
301 * Move this line down in its parent's children.
303 public void moveDown() {
304 if (parentInput
!= null) {
305 int index
= parentInput
.childrenInputs
.indexOf(this);
306 if (index
< parentInput
.childrenInputs
.size() - 1) {
307 parentInput
.childrenInputs
.add(index
+ 1, parentInput
.childrenInputs
.remove(index
));
308 nextInput
= parentInput
.childrenInputs
.get(index
).nextInput
;
309 parentInput
.childrenInputs
.get(index
).nextInput
= this;
315 * Add a data column to this line
320 public void addColumn(InputData column
) {
321 if (columns
== null) {
322 columns
= new ArrayList
<>(1);
328 * Get the next input lines.
331 * The map of line "sets".
332 * @return The next list of lines.
334 public List
<InputLine
> getNextInputs(Map
<InputLine
, Integer
> countMap
) {
335 List
<InputLine
> nextInputs
= new ArrayList
<>();
336 InputLine next
= nextInput
;
337 while (next
!= null) {
338 nextInputs
.add(next
);
339 if (next
.cardinality
.min
> 0) {
342 next
= next
.nextInput
;
344 if (parentInput
!= null && parentInput
.level
> 0) {
345 int parentCount
= countMap
.get(parentInput
);
346 if (parentCount
< parentInput
.getMaxCount()) {
347 nextInputs
.add(parentInput
);
349 if (parentCount
< parentInput
.getMinCount()) {
352 nextInputs
.addAll(parentInput
.getNextInputs(countMap
));
358 * Get the minimum possible amount of entries.
360 * @return The minimum
362 public int getMinCount() {
363 return cardinality
.min
;
367 * Get the maximum possible amount of entries.
369 * @return The maximum
371 public int getMaxCount() {
372 return cardinality
.max
;
376 public String
toString() {
377 return regex
+ " " + cardinality
; //$NON-NLS-1$
382 * Data column for input lines.
384 public static class InputData
{
386 /** Name of this column */
393 public String format
;
396 * Default (empty) constructor
411 public InputData(String name
, int action
, String format
) {
413 this.action
= action
;
414 this.format
= format
;
418 * Constructor with default format
425 public InputData(String name
, int action
) {
427 this.action
= action
;
432 * Input line cardinality
434 public static class Cardinality
{
436 /** Representation of infinity */
437 public final static int INF
= Integer
.MAX_VALUE
;
439 /** Preset for [1, 1] */
440 public final static Cardinality ONE
= new Cardinality(1, 1);
442 /** Preset for [1, inf] */
443 public final static Cardinality ONE_OR_MORE
= new Cardinality(1, INF
);
445 /** Preset for [0, 1] */
446 public final static Cardinality ZERO_OR_ONE
= new Cardinality(0, 1);
448 /** Preset for [0, inf] */
449 public final static Cardinality ZERO_OR_MORE
= new Cardinality(0, INF
);
451 private final int min
;
452 private final int max
;
462 public Cardinality(int min
, int max
) {
468 public String
toString() {
469 return "(" + (min
>= 0 ? min
: "?") + ',' + (max
== INF ?
"\u221E" : (max
>= 0 ? max
: "?")) + ')'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
473 public int hashCode() {
474 final int prime
= 31;
476 result
= prime
* result
+ max
;
477 result
= prime
* result
+ min
;
482 public boolean equals(Object obj
) {
489 if (!(obj
instanceof Cardinality
)) {
492 Cardinality other
= (Cardinality
) obj
;
493 return (this.min
== other
.min
&& this.max
== other
.max
);
499 save(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
503 public void save(String path
) {
505 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
506 DocumentBuilder db
= dbf
.newDocumentBuilder();
508 // The following allows xml parsing without access to the dtd
509 db
.setEntityResolver(createEmptyEntityResolver());
511 // The following catches xml parsing exceptions
512 db
.setErrorHandler(createErrorHandler());
515 File file
= new File(path
);
516 if (file
.canRead()) {
517 doc
= db
.parse(file
);
518 if (!doc
.getDocumentElement().getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
522 doc
= db
.newDocument();
523 Node node
= doc
.createElement(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
);
524 doc
.appendChild(node
);
527 Element root
= doc
.getDocumentElement();
529 Element oldDefinitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
530 if (oldDefinitionElement
!= null) {
531 root
.removeChild(oldDefinitionElement
);
533 Element definitionElement
= doc
.createElement(DEFINITION_ELEMENT
);
534 root
.appendChild(definitionElement
);
535 definitionElement
.setAttribute(CATEGORY_ATTRIBUTE
, categoryName
);
536 definitionElement
.setAttribute(NAME_ATTRIBUTE
, definitionName
);
538 Element formatElement
= doc
.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
);
539 definitionElement
.appendChild(formatElement
);
540 formatElement
.appendChild(doc
.createTextNode(timeStampOutputFormat
));
542 if (inputs
!= null) {
543 for (InputLine inputLine
: inputs
) {
544 definitionElement
.appendChild(createInputLineElement(inputLine
, doc
));
548 if (outputs
!= null) {
549 for (OutputColumn output
: outputs
) {
550 Element outputColumnElement
= doc
.createElement(OUTPUT_COLUMN_ELEMENT
);
551 definitionElement
.appendChild(outputColumnElement
);
552 outputColumnElement
.setAttribute(NAME_ATTRIBUTE
, output
.name
);
556 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
557 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
559 // initialize StreamResult with File object to save to file
560 StreamResult result
= new StreamResult(new StringWriter());
561 DOMSource source
= new DOMSource(doc
);
562 transformer
.transform(source
, result
);
563 String xmlString
= result
.getWriter().toString();
565 try (FileWriter writer
= new FileWriter(file
);) {
566 writer
.write(xmlString
);
569 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
571 } catch (ParserConfigurationException e
) {
572 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
573 } catch (TransformerConfigurationException e
) {
574 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
575 } catch (TransformerFactoryConfigurationError e
) {
576 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
577 } catch (TransformerException e
) {
578 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
579 } catch (IOException e
) {
580 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
581 } catch (SAXException e
) {
582 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
586 private Element
createInputLineElement(InputLine inputLine
, Document doc
) {
587 Element inputLineElement
= doc
.createElement(INPUT_LINE_ELEMENT
);
589 Element cardinalityElement
= doc
.createElement(CARDINALITY_ELEMENT
);
590 inputLineElement
.appendChild(cardinalityElement
);
591 cardinalityElement
.setAttribute(MIN_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.min
));
592 cardinalityElement
.setAttribute(MAX_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.max
));
594 Element regexElement
= doc
.createElement(REGEX_ELEMENT
);
595 inputLineElement
.appendChild(regexElement
);
596 regexElement
.appendChild(doc
.createTextNode(inputLine
.regex
));
598 if (inputLine
.columns
!= null) {
599 for (InputData inputData
: inputLine
.columns
) {
600 Element inputDataElement
= doc
.createElement(INPUT_DATA_ELEMENT
);
601 inputLineElement
.appendChild(inputDataElement
);
602 inputDataElement
.setAttribute(NAME_ATTRIBUTE
, inputData
.name
);
603 inputDataElement
.setAttribute(ACTION_ATTRIBUTE
, Integer
.toString(inputData
.action
));
604 if (inputData
.format
!= null) {
605 inputDataElement
.setAttribute(FORMAT_ATTRIBUTE
, inputData
.format
);
610 if (inputLine
.childrenInputs
!= null) {
611 for (InputLine childInputLine
: inputLine
.childrenInputs
) {
612 inputLineElement
.appendChild(createInputLineElement(childInputLine
, doc
));
616 return inputLineElement
;
620 * Load all custom text trace definitions, including the user-defined and
621 * default (built-in) parsers.
623 * @return The loaded trace definitions
625 public static CustomTxtTraceDefinition
[] loadAll() {
626 return loadAll(true);
630 * Load all custom text trace definitions, including the user-defined and,
631 * optionally, the default (built-in) parsers.
633 * @param includeDefaults
634 * if true, the default (built-in) parsers are included
636 * @return The loaded trace definitions
639 public static CustomTxtTraceDefinition
[] loadAll(boolean includeDefaults
) {
640 File defaultFile
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
641 File legacyFileCore
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
642 File legacyFileUI
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
645 * If there is no file at the expected location, check the legacy
648 if (!defaultFile
.exists()) {
649 if (legacyFileCore
.exists()) {
650 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE
);
651 } else if (legacyFileUI
.exists()) {
652 transferDefinitions(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI
);
656 Set
<CustomTxtTraceDefinition
> defs
= new TreeSet
<>(new Comparator
<CustomTxtTraceDefinition
>() {
658 public int compare(CustomTxtTraceDefinition o1
, CustomTxtTraceDefinition o2
) {
659 int result
= o1
.categoryName
.compareTo(o2
.categoryName
);
663 return o1
.definitionName
.compareTo(o2
.definitionName
);
666 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
)));
667 if (includeDefaults
) {
668 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
)));
670 return defs
.toArray(new CustomTxtTraceDefinition
[0]);
674 private static void transferDefinitions(String defFile
) {
675 CustomTxtTraceDefinition
[] oldDefs
= loadAll(defFile
);
676 for (CustomTxtTraceDefinition def
: oldDefs
) {
677 /* Save in the new location */
683 * Load a specific text trace definition file.
686 * The path to the file to load
687 * @return The loaded trace definitions
689 public static CustomTxtTraceDefinition
[] loadAll(String path
) {
691 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
692 DocumentBuilder db
= dbf
.newDocumentBuilder();
694 // The following allows xml parsing without access to the dtd
695 db
.setEntityResolver(createEmptyEntityResolver());
697 // The following catches xml parsing exceptions
698 db
.setErrorHandler(createErrorHandler());
700 File file
= new File(path
);
701 if (!file
.canRead()) {
702 return new CustomTxtTraceDefinition
[0];
704 Document doc
= db
.parse(file
);
706 Element root
= doc
.getDocumentElement();
707 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
708 return new CustomTxtTraceDefinition
[0];
711 ArrayList
<CustomTxtTraceDefinition
> defList
= new ArrayList
<>();
712 NodeList nodeList
= root
.getChildNodes();
713 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
714 Node node
= nodeList
.item(i
);
715 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
716 CustomTxtTraceDefinition def
= extractDefinition((Element
) node
);
722 return defList
.toArray(new CustomTxtTraceDefinition
[0]);
723 } catch (ParserConfigurationException e
) {
724 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
725 } catch (SAXException e
) {
726 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
727 } catch (IOException e
) {
728 Activator
.logError("Error loading all in CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
730 return new CustomTxtTraceDefinition
[0];
734 * Load a single definition.
736 * @param definitionName
737 * Name of the definition to load
738 * @return The loaded trace definition
739 * @deprecated Use {@link #load(String, String)}
742 public static CustomTxtTraceDefinition
load(String definitionName
) {
743 return load(CUSTOM_TXT_CATEGORY
, definitionName
);
747 * Load a single definition.
749 * @param categoryName
750 * Category of the definition to load
751 * @param definitionName
752 * Name of the definition to load
753 * @return The loaded trace definition
756 public static CustomTxtTraceDefinition
load(String categoryName
, String definitionName
) {
758 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
759 DocumentBuilder db
= dbf
.newDocumentBuilder();
761 // The following allows xml parsing without access to the dtd
762 db
.setEntityResolver(createEmptyEntityResolver());
764 // The following catches xml parsing exceptions
765 db
.setErrorHandler(createErrorHandler());
767 CustomTxtTraceDefinition value
= lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
769 return lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
);
772 } catch (ParserConfigurationException
| SAXException
| IOException e
) {
773 Activator
.logError("Error loading CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$
778 private static CustomTxtTraceDefinition
lookupDefinition(String categoryName
, String definitionName
, DocumentBuilder db
, String source
) throws SAXException
, IOException
{
779 File file
= new File(source
);
780 if (!file
.exists()) {
783 Document doc
= db
.parse(file
);
785 Element root
= doc
.getDocumentElement();
786 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
790 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
791 if (definitionElement
!= null) {
792 return extractDefinition(definitionElement
);
797 private static Element
findDefinitionElement(Element root
, String categoryName
, String definitionName
) {
798 NodeList nodeList
= root
.getChildNodes();
799 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
800 Node node
= nodeList
.item(i
);
801 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
802 Element element
= (Element
) node
;
803 String categoryAttribute
= element
.getAttribute(CATEGORY_ATTRIBUTE
);
804 if (categoryAttribute
.isEmpty()) {
805 categoryAttribute
= CUSTOM_TXT_CATEGORY
;
807 String nameAttribute
= element
.getAttribute(NAME_ATTRIBUTE
);
808 if (categoryName
.equals(categoryAttribute
) &&
809 definitionName
.equals(nameAttribute
)) {
818 * Get the definition from a definition element.
820 * @param definitionElement
821 * The Element to extract from
822 * @return The loaded trace definition
824 public static CustomTxtTraceDefinition
extractDefinition(Element definitionElement
) {
825 CustomTxtTraceDefinition def
= new CustomTxtTraceDefinition();
827 def
.categoryName
= definitionElement
.getAttribute(CATEGORY_ATTRIBUTE
);
828 if (def
.categoryName
.isEmpty()) {
829 def
.categoryName
= CUSTOM_TXT_CATEGORY
;
831 def
.definitionName
= definitionElement
.getAttribute(NAME_ATTRIBUTE
);
832 if (def
.definitionName
.isEmpty()) {
836 NodeList nodeList
= definitionElement
.getChildNodes();
837 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
838 Node node
= nodeList
.item(i
);
839 String nodeName
= node
.getNodeName();
840 if (nodeName
.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
)) {
841 Element formatElement
= (Element
) node
;
842 def
.timeStampOutputFormat
= formatElement
.getTextContent();
843 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
844 InputLine inputLine
= extractInputLine((Element
) node
);
845 if (inputLine
!= null) {
846 def
.inputs
.add(inputLine
);
848 } else if (nodeName
.equals(OUTPUT_COLUMN_ELEMENT
)) {
849 Element outputColumnElement
= (Element
) node
;
850 OutputColumn outputColumn
= new OutputColumn();
851 outputColumn
.name
= outputColumnElement
.getAttribute(NAME_ATTRIBUTE
);
852 def
.outputs
.add(outputColumn
);
858 private static InputLine
extractInputLine(Element inputLineElement
) {
859 InputLine inputLine
= new InputLine();
860 NodeList nodeList
= inputLineElement
.getChildNodes();
861 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
862 Node node
= nodeList
.item(i
);
863 String nodeName
= node
.getNodeName();
864 if (nodeName
.equals(CARDINALITY_ELEMENT
)) {
865 Element cardinalityElement
= (Element
) node
;
867 int min
= Integer
.parseInt(cardinalityElement
.getAttribute(MIN_ATTRIBUTE
));
868 int max
= Integer
.parseInt(cardinalityElement
.getAttribute(MAX_ATTRIBUTE
));
869 inputLine
.cardinality
= new Cardinality(min
, max
);
870 } catch (NumberFormatException e
) {
873 } else if (nodeName
.equals(REGEX_ELEMENT
)) {
874 Element regexElement
= (Element
) node
;
875 inputLine
.regex
= regexElement
.getTextContent();
876 } else if (nodeName
.equals(INPUT_DATA_ELEMENT
)) {
877 Element inputDataElement
= (Element
) node
;
878 InputData inputData
= new InputData();
879 inputData
.name
= inputDataElement
.getAttribute(NAME_ATTRIBUTE
);
880 inputData
.action
= Integer
.parseInt(inputDataElement
.getAttribute(ACTION_ATTRIBUTE
));
881 inputData
.format
= inputDataElement
.getAttribute(FORMAT_ATTRIBUTE
);
882 inputLine
.addColumn(inputData
);
883 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
884 Element childInputLineElement
= (Element
) node
;
885 InputLine childInputLine
= extractInputLine(childInputLineElement
);
886 if (childInputLine
!= null) {
887 inputLine
.addChild(childInputLine
);
895 * Delete a definition from the currently loaded ones.
897 * @param definitionName
898 * The name of the definition to delete
899 * @deprecated Use {@link #delete(String, String)}
902 public static void delete(String definitionName
) {
903 delete(CUSTOM_TXT_CATEGORY
, definitionName
);
907 * Delete a definition from the currently loaded ones.
909 * @param categoryName
910 * The category of the definition to delete
911 * @param definitionName
912 * The name of the definition to delete
915 public static void delete(String categoryName
, String definitionName
) {
917 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
918 DocumentBuilder db
= dbf
.newDocumentBuilder();
920 // The following allows xml parsing without access to the dtd
921 db
.setEntityResolver(createEmptyEntityResolver());
923 // The following catches xml parsing exceptions
924 db
.setErrorHandler(createErrorHandler());
926 File file
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
927 Document doc
= db
.parse(file
);
929 Element root
= doc
.getDocumentElement();
930 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
934 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
935 if (definitionElement
!= null) {
936 root
.removeChild(definitionElement
);
939 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
940 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
942 // initialize StreamResult with File object to save to file
943 StreamResult result
= new StreamResult(new StringWriter());
944 DOMSource source
= new DOMSource(doc
);
945 transformer
.transform(source
, result
);
946 String xmlString
= result
.getWriter().toString();
948 try (FileWriter writer
= new FileWriter(file
);) {
949 writer
.write(xmlString
);
952 TmfTraceType
.removeCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
953 // Check if default definition needs to be reloaded
954 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
956 } catch (ParserConfigurationException
| SAXException
| IOException
| TransformerFactoryConfigurationError
| TransformerException e
) {
957 Activator
.logError("Error deleting CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$