1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 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
.linuxtools
.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
.linuxtools
.internal
.tmf
.core
.Activator
;
44 import org
.eclipse
.linuxtools
.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
;
62 /** File name of the default definition file */
63 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
= "custom_txt_default_parsers.xml"; //$NON-NLS-1$
64 /** File name of the definition file */
65 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
= "custom_txt_parsers.xml"; //$NON-NLS-1$
67 /** Path of the definition file */
68 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
=
69 Platform
.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
70 CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_FILE_NAME
;
71 /** Path of the definition file */
72 protected static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
=
73 Activator
.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
76 * Legacy path to the XML definitions file (in the UI plug-in) TODO Remove
77 * once we feel the transition phase is over.
79 private static final String CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY
=
80 Activator
.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
81 .append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
82 .append(CUSTOM_TXT_TRACE_DEFINITIONS_FILE_NAME
).toString();
84 private static final String CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
= Messages
.CustomTxtTraceDefinition_definitionRootElement
;
85 private static final String DEFINITION_ELEMENT
= Messages
.CustomTxtTraceDefinition_definition
;
86 private static final String CATEGORY_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_category
;
87 private static final String NAME_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_name
;
88 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT
= Messages
.CustomTxtTraceDefinition_timestampOutputFormat
;
89 private static final String INPUT_LINE_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputLine
;
90 private static final String CARDINALITY_ELEMENT
= Messages
.CustomTxtTraceDefinition_cardinality
;
91 private static final String MIN_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_min
;
92 private static final String MAX_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_max
;
93 private static final String REGEX_ELEMENT
= Messages
.CustomTxtTraceDefinition_regEx
;
94 private static final String INPUT_DATA_ELEMENT
= Messages
.CustomTxtTraceDefinition_inputData
;
95 private static final String ACTION_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_action
;
96 private static final String FORMAT_ATTRIBUTE
= Messages
.CustomTxtTraceDefinition_format
;
97 private static final String OUTPUT_COLUMN_ELEMENT
= Messages
.CustomTxtTraceDefinition_outputColumn
;
100 * Default constructor.
102 public CustomTxtTraceDefinition() {
103 this(TmfTraceType
.CUSTOM_TXT_CATEGORY
, "", new ArrayList
<InputLine
>(0), new ArrayList
<OutputColumn
>(0), ""); //$NON-NLS-1$ //$NON-NLS-2$
110 * Name of the trace type
114 * List of output columns
115 * @param timeStampOutputFormat
116 * The timestamp format to use
117 * @deprecated Use {@link #CustomTxtTraceDefinition(String, String, List, List, String)}
120 public CustomTxtTraceDefinition(String traceType
, List
<InputLine
> inputs
,
121 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
122 this.definitionName
= traceType
;
123 this.inputs
= inputs
;
124 this.outputs
= outputs
;
125 this.timeStampOutputFormat
= timeStampOutputFormat
;
132 * Category of the trace type
134 * Name of the trace type
138 * List of output columns
139 * @param timeStampOutputFormat
140 * The timestamp format to use
143 public CustomTxtTraceDefinition(String category
, String traceType
, List
<InputLine
> inputs
,
144 List
<OutputColumn
> outputs
, String timeStampOutputFormat
) {
145 this.categoryName
= category
;
146 this.definitionName
= traceType
;
147 this.inputs
= inputs
;
148 this.outputs
= outputs
;
149 this.timeStampOutputFormat
= timeStampOutputFormat
;
153 * Wrapper to store a line of the log file
155 public static class InputLine
{
157 /** Data columns of this line */
158 public List
<InputData
> columns
;
160 /** Cardinality of this line (see {@link Cardinality}) */
161 public Cardinality cardinality
;
164 public InputLine parentInput
;
166 /** Level of this line */
169 /** Next input line in the file */
170 public InputLine nextInput
;
172 /** Children of this line (if one "event" spans many lines) */
173 public List
<InputLine
> childrenInputs
;
175 private String regex
;
176 private Pattern pattern
;
179 * Default (empty) constructor.
188 * Cardinality of this line.
194 public InputLine(Cardinality cardinality
, String regex
, List
<InputData
> columns
) {
195 this.cardinality
= cardinality
;
197 this.columns
= columns
;
201 * Set the regex of this input line
206 public void setRegex(String regex
) {
212 * Get the current regex
214 * @return The current regex
216 public String
getRegex() {
221 * Get the Pattern object of this line's regex
223 * @return The Pattern
224 * @throws PatternSyntaxException
225 * If the regex does not parse correctly
227 public Pattern
getPattern() throws PatternSyntaxException
{
228 if (pattern
== null) {
229 pattern
= Pattern
.compile(regex
);
235 * Add a child line to this line.
238 * The child input line
240 public void addChild(InputLine input
) {
241 if (childrenInputs
== null) {
242 childrenInputs
= new ArrayList
<>(1);
243 } else if (childrenInputs
.size() > 0) {
244 InputLine last
= childrenInputs
.get(childrenInputs
.size() - 1);
245 last
.nextInput
= input
;
247 childrenInputs
.add(input
);
248 input
.parentInput
= this;
249 input
.level
= this.level
+ 1;
253 * Set the next input line.
256 * The next input line
258 public void addNext(InputLine input
) {
259 if (parentInput
!= null) {
260 int index
= parentInput
.childrenInputs
.indexOf(this);
261 parentInput
.childrenInputs
.add(index
+ 1, input
);
262 InputLine next
= nextInput
;
264 input
.nextInput
= next
;
266 input
.parentInput
= this.parentInput
;
267 input
.level
= this.level
;
271 * Move this line up in its parent's children.
273 public void moveUp() {
274 if (parentInput
!= null) {
275 int index
= parentInput
.childrenInputs
.indexOf(this);
277 parentInput
.childrenInputs
.add(index
- 1, parentInput
.childrenInputs
.remove(index
));
278 parentInput
.childrenInputs
.get(index
).nextInput
= nextInput
;
279 nextInput
= parentInput
.childrenInputs
.get(index
);
285 * Move this line down in its parent's children.
287 public void moveDown() {
288 if (parentInput
!= null) {
289 int index
= parentInput
.childrenInputs
.indexOf(this);
290 if (index
< parentInput
.childrenInputs
.size() - 1) {
291 parentInput
.childrenInputs
.add(index
+ 1, parentInput
.childrenInputs
.remove(index
));
292 nextInput
= parentInput
.childrenInputs
.get(index
).nextInput
;
293 parentInput
.childrenInputs
.get(index
).nextInput
= this;
299 * Add a data column to this line
304 public void addColumn(InputData column
) {
305 if (columns
== null) {
306 columns
= new ArrayList
<>(1);
312 * Get the next input lines.
315 * The map of line "sets".
316 * @return The next list of lines.
318 public List
<InputLine
> getNextInputs(Map
<InputLine
, Integer
> countMap
) {
319 List
<InputLine
> nextInputs
= new ArrayList
<>();
320 InputLine next
= nextInput
;
321 while (next
!= null) {
322 nextInputs
.add(next
);
323 if (next
.cardinality
.min
> 0) {
326 next
= next
.nextInput
;
328 if (parentInput
!= null && parentInput
.level
> 0) {
329 int parentCount
= countMap
.get(parentInput
);
330 if (parentCount
< parentInput
.getMaxCount()) {
331 nextInputs
.add(parentInput
);
333 if (parentCount
< parentInput
.getMinCount()) {
336 nextInputs
.addAll(parentInput
.getNextInputs(countMap
));
342 * Get the minimum possible amount of entries.
344 * @return The minimum
346 public int getMinCount() {
347 return cardinality
.min
;
351 * Get the maximum possible amount of entries.
353 * @return The maximum
355 public int getMaxCount() {
356 return cardinality
.max
;
360 public String
toString() {
361 return regex
+ " " + cardinality
; //$NON-NLS-1$
366 * Data column for input lines.
368 public static class InputData
{
370 /** Name of this column */
377 public String format
;
380 * Default (empty) constructor
395 public InputData(String name
, int action
, String format
) {
397 this.action
= action
;
398 this.format
= format
;
402 * Constructor with default format
409 public InputData(String name
, int action
) {
411 this.action
= action
;
416 * Input line cardinality
418 public static class Cardinality
{
420 /** Representation of infinity */
421 public final static int INF
= Integer
.MAX_VALUE
;
423 /** Preset for [1, 1] */
424 public final static Cardinality ONE
= new Cardinality(1, 1);
426 /** Preset for [1, inf] */
427 public final static Cardinality ONE_OR_MORE
= new Cardinality(1, INF
);
429 /** Preset for [0, 1] */
430 public final static Cardinality ZERO_OR_ONE
= new Cardinality(0, 1);
432 /** Preset for [0, inf] */
433 public final static Cardinality ZERO_OR_MORE
= new Cardinality(0, INF
);
435 private final int min
;
436 private final int max
;
446 public Cardinality(int min
, int max
) {
452 public String
toString() {
453 return "(" + (min
>= 0 ? min
: "?") + ',' + (max
== INF ?
"\u221E" : (max
>= 0 ? max
: "?")) + ')'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
457 public int hashCode() {
458 final int prime
= 31;
460 result
= prime
* result
+ max
;
461 result
= prime
* result
+ min
;
466 public boolean equals(Object obj
) {
473 if (!(obj
instanceof Cardinality
)) {
476 Cardinality other
= (Cardinality
) obj
;
477 return (this.min
== other
.min
&& this.max
== other
.max
);
483 save(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
487 public void save(String path
) {
489 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
490 DocumentBuilder db
= dbf
.newDocumentBuilder();
492 // The following allows xml parsing without access to the dtd
493 db
.setEntityResolver(createEmptyEntityResolver());
495 // The following catches xml parsing exceptions
496 db
.setErrorHandler(createErrorHandler());
499 File file
= new File(path
);
500 if (file
.canRead()) {
501 doc
= db
.parse(file
);
502 if (!doc
.getDocumentElement().getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
506 doc
= db
.newDocument();
507 Node node
= doc
.createElement(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
);
508 doc
.appendChild(node
);
511 Element root
= doc
.getDocumentElement();
513 Element oldDefinitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
514 if (oldDefinitionElement
!= null) {
515 root
.removeChild(oldDefinitionElement
);
517 Element definitionElement
= doc
.createElement(DEFINITION_ELEMENT
);
518 root
.appendChild(definitionElement
);
519 definitionElement
.setAttribute(CATEGORY_ATTRIBUTE
, categoryName
);
520 definitionElement
.setAttribute(NAME_ATTRIBUTE
, definitionName
);
522 Element formatElement
= doc
.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
);
523 definitionElement
.appendChild(formatElement
);
524 formatElement
.appendChild(doc
.createTextNode(timeStampOutputFormat
));
526 if (inputs
!= null) {
527 for (InputLine inputLine
: inputs
) {
528 definitionElement
.appendChild(createInputLineElement(inputLine
, doc
));
532 if (outputs
!= null) {
533 for (OutputColumn output
: outputs
) {
534 Element outputColumnElement
= doc
.createElement(OUTPUT_COLUMN_ELEMENT
);
535 definitionElement
.appendChild(outputColumnElement
);
536 outputColumnElement
.setAttribute(NAME_ATTRIBUTE
, output
.name
);
540 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
541 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
543 // initialize StreamResult with File object to save to file
544 StreamResult result
= new StreamResult(new StringWriter());
545 DOMSource source
= new DOMSource(doc
);
546 transformer
.transform(source
, result
);
547 String xmlString
= result
.getWriter().toString();
549 try (FileWriter writer
= new FileWriter(file
);) {
550 writer
.write(xmlString
);
553 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
555 } catch (ParserConfigurationException e
) {
556 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
557 } catch (TransformerConfigurationException e
) {
558 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
559 } catch (TransformerFactoryConfigurationError e
) {
560 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
561 } catch (TransformerException e
) {
562 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
563 } catch (IOException e
) {
564 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
565 } catch (SAXException e
) {
566 Activator
.logError("Error saving CustomTxtTraceDefinition: path=" + path
, e
); //$NON-NLS-1$
570 private Element
createInputLineElement(InputLine inputLine
, Document doc
) {
571 Element inputLineElement
= doc
.createElement(INPUT_LINE_ELEMENT
);
573 Element cardinalityElement
= doc
.createElement(CARDINALITY_ELEMENT
);
574 inputLineElement
.appendChild(cardinalityElement
);
575 cardinalityElement
.setAttribute(MIN_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.min
));
576 cardinalityElement
.setAttribute(MAX_ATTRIBUTE
, Integer
.toString(inputLine
.cardinality
.max
));
578 Element regexElement
= doc
.createElement(REGEX_ELEMENT
);
579 inputLineElement
.appendChild(regexElement
);
580 regexElement
.appendChild(doc
.createTextNode(inputLine
.regex
));
582 if (inputLine
.columns
!= null) {
583 for (InputData inputData
: inputLine
.columns
) {
584 Element inputDataElement
= doc
.createElement(INPUT_DATA_ELEMENT
);
585 inputLineElement
.appendChild(inputDataElement
);
586 inputDataElement
.setAttribute(NAME_ATTRIBUTE
, inputData
.name
);
587 inputDataElement
.setAttribute(ACTION_ATTRIBUTE
, Integer
.toString(inputData
.action
));
588 if (inputData
.format
!= null) {
589 inputDataElement
.setAttribute(FORMAT_ATTRIBUTE
, inputData
.format
);
594 if (inputLine
.childrenInputs
!= null) {
595 for (InputLine childInputLine
: inputLine
.childrenInputs
) {
596 inputLineElement
.appendChild(createInputLineElement(childInputLine
, doc
));
600 return inputLineElement
;
604 * Load all custom text trace definitions, including the user-defined and
605 * default (built-in) parsers.
607 * @return The loaded trace definitions
609 public static CustomTxtTraceDefinition
[] loadAll() {
610 return loadAll(true);
614 * Load all custom text trace definitions, including the user-defined and,
615 * optionally, the default (built-in) parsers.
617 * @param includeDefaults
618 * if true, the default (built-in) parsers are included
620 * @return The loaded trace definitions
623 public static CustomTxtTraceDefinition
[] loadAll(boolean includeDefaults
) {
624 File defaultFile
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
625 File legacyFile
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY
);
628 * If there is no file at the expected location, check the legacy
631 if (!defaultFile
.exists() && legacyFile
.exists()) {
632 CustomTxtTraceDefinition
[] oldDefs
= loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY
);
633 for (CustomTxtTraceDefinition def
: oldDefs
) {
634 /* Save in the new location */
639 Set
<CustomTxtTraceDefinition
> defs
= new TreeSet
<>(new Comparator
<CustomTxtTraceDefinition
>() {
641 public int compare(CustomTxtTraceDefinition o1
, CustomTxtTraceDefinition o2
) {
642 int result
= o1
.categoryName
.compareTo(o2
.categoryName
);
646 return o1
.definitionName
.compareTo(o2
.definitionName
);
649 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
)));
650 if (includeDefaults
) {
651 defs
.addAll(Arrays
.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
)));
653 return defs
.toArray(new CustomTxtTraceDefinition
[0]);
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 definitionName
712 * Name of the definition to load
713 * @return The loaded trace definition
714 * @deprecated Use {@link #load(String, String)}
717 public static CustomTxtTraceDefinition
load(String definitionName
) {
718 return load(TmfTraceType
.CUSTOM_TXT_CATEGORY
, definitionName
);
722 * Load a single definition.
724 * @param categoryName
725 * Category of the definition to load
726 * @param definitionName
727 * Name of the definition to load
728 * @return The loaded trace definition
731 public static CustomTxtTraceDefinition
load(String categoryName
, String definitionName
) {
733 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
734 DocumentBuilder db
= dbf
.newDocumentBuilder();
736 // The following allows xml parsing without access to the dtd
737 db
.setEntityResolver(createEmptyEntityResolver());
739 // The following catches xml parsing exceptions
740 db
.setErrorHandler(createErrorHandler());
742 CustomTxtTraceDefinition value
= lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
744 return lookupDefinition(categoryName
, definitionName
, db
, CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME
);
747 } catch (ParserConfigurationException
| SAXException
| IOException e
) {
748 Activator
.logError("Error loading CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$
753 private static CustomTxtTraceDefinition
lookupDefinition(String categoryName
, String definitionName
, DocumentBuilder db
, String source
) throws SAXException
, IOException
{
754 File file
= new File(source
);
755 if (!file
.exists()) {
758 Document doc
= db
.parse(file
);
760 Element root
= doc
.getDocumentElement();
761 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
765 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
766 if (definitionElement
!= null) {
767 return extractDefinition(definitionElement
);
772 private static Element
findDefinitionElement(Element root
, String categoryName
, String definitionName
) {
773 NodeList nodeList
= root
.getChildNodes();
774 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
775 Node node
= nodeList
.item(i
);
776 if (node
instanceof Element
&& node
.getNodeName().equals(DEFINITION_ELEMENT
)) {
777 Element element
= (Element
) node
;
778 String categoryAttribute
= element
.getAttribute(CATEGORY_ATTRIBUTE
);
779 if (categoryAttribute
.isEmpty()) {
780 categoryAttribute
= TmfTraceType
.CUSTOM_TXT_CATEGORY
;
782 String nameAttribute
= element
.getAttribute(NAME_ATTRIBUTE
);
783 if (categoryName
.equals(categoryAttribute
) &&
784 definitionName
.equals(nameAttribute
)) {
793 * Get the definition from a definition element.
795 * @param definitionElement
796 * The Element to extract from
797 * @return The loaded trace definition
799 public static CustomTxtTraceDefinition
extractDefinition(Element definitionElement
) {
800 CustomTxtTraceDefinition def
= new CustomTxtTraceDefinition();
802 def
.categoryName
= definitionElement
.getAttribute(CATEGORY_ATTRIBUTE
);
803 if (def
.categoryName
.isEmpty()) {
804 def
.categoryName
= TmfTraceType
.CUSTOM_TXT_CATEGORY
;
806 def
.definitionName
= definitionElement
.getAttribute(NAME_ATTRIBUTE
);
807 if (def
.definitionName
.isEmpty()) {
811 NodeList nodeList
= definitionElement
.getChildNodes();
812 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
813 Node node
= nodeList
.item(i
);
814 String nodeName
= node
.getNodeName();
815 if (nodeName
.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT
)) {
816 Element formatElement
= (Element
) node
;
817 def
.timeStampOutputFormat
= formatElement
.getTextContent();
818 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
819 InputLine inputLine
= extractInputLine((Element
) node
);
820 if (inputLine
!= null) {
821 def
.inputs
.add(inputLine
);
823 } else if (nodeName
.equals(OUTPUT_COLUMN_ELEMENT
)) {
824 Element outputColumnElement
= (Element
) node
;
825 OutputColumn outputColumn
= new OutputColumn();
826 outputColumn
.name
= outputColumnElement
.getAttribute(NAME_ATTRIBUTE
);
827 def
.outputs
.add(outputColumn
);
833 private static InputLine
extractInputLine(Element inputLineElement
) {
834 InputLine inputLine
= new InputLine();
835 NodeList nodeList
= inputLineElement
.getChildNodes();
836 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
837 Node node
= nodeList
.item(i
);
838 String nodeName
= node
.getNodeName();
839 if (nodeName
.equals(CARDINALITY_ELEMENT
)) {
840 Element cardinalityElement
= (Element
) node
;
842 int min
= Integer
.parseInt(cardinalityElement
.getAttribute(MIN_ATTRIBUTE
));
843 int max
= Integer
.parseInt(cardinalityElement
.getAttribute(MAX_ATTRIBUTE
));
844 inputLine
.cardinality
= new Cardinality(min
, max
);
845 } catch (NumberFormatException e
) {
848 } else if (nodeName
.equals(REGEX_ELEMENT
)) {
849 Element regexElement
= (Element
) node
;
850 inputLine
.regex
= regexElement
.getTextContent();
851 } else if (nodeName
.equals(INPUT_DATA_ELEMENT
)) {
852 Element inputDataElement
= (Element
) node
;
853 InputData inputData
= new InputData();
854 inputData
.name
= inputDataElement
.getAttribute(NAME_ATTRIBUTE
);
855 inputData
.action
= Integer
.parseInt(inputDataElement
.getAttribute(ACTION_ATTRIBUTE
));
856 inputData
.format
= inputDataElement
.getAttribute(FORMAT_ATTRIBUTE
);
857 inputLine
.addColumn(inputData
);
858 } else if (nodeName
.equals(INPUT_LINE_ELEMENT
)) {
859 Element childInputLineElement
= (Element
) node
;
860 InputLine childInputLine
= extractInputLine(childInputLineElement
);
861 if (childInputLine
!= null) {
862 inputLine
.addChild(childInputLine
);
870 * Delete a definition from the currently loaded ones.
872 * @param definitionName
873 * The name of the definition to delete
874 * @deprecated Use {@link #delete(String, String)}
877 public static void delete(String definitionName
) {
878 delete(TmfTraceType
.CUSTOM_TXT_CATEGORY
, definitionName
);
882 * Delete a definition from the currently loaded ones.
884 * @param categoryName
885 * The category of the definition to delete
886 * @param definitionName
887 * The name of the definition to delete
890 public static void delete(String categoryName
, String definitionName
) {
892 DocumentBuilderFactory dbf
= DocumentBuilderFactory
.newInstance();
893 DocumentBuilder db
= dbf
.newDocumentBuilder();
895 // The following allows xml parsing without access to the dtd
896 db
.setEntityResolver(createEmptyEntityResolver());
898 // The following catches xml parsing exceptions
899 db
.setErrorHandler(createErrorHandler());
901 File file
= new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME
);
902 Document doc
= db
.parse(file
);
904 Element root
= doc
.getDocumentElement();
905 if (!root
.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT
)) {
909 Element definitionElement
= findDefinitionElement(root
, categoryName
, definitionName
);
910 if (definitionElement
!= null) {
911 root
.removeChild(definitionElement
);
914 Transformer transformer
= TransformerFactory
.newInstance().newTransformer();
915 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes"); //$NON-NLS-1$
917 // initialize StreamResult with File object to save to file
918 StreamResult result
= new StreamResult(new StringWriter());
919 DOMSource source
= new DOMSource(doc
);
920 transformer
.transform(source
, result
);
921 String xmlString
= result
.getWriter().toString();
923 try (FileWriter writer
= new FileWriter(file
);) {
924 writer
.write(xmlString
);
927 TmfTraceType
.removeCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
928 // Check if default definition needs to be reloaded
929 TmfTraceType
.addCustomTraceType(CustomTxtTrace
.class, categoryName
, definitionName
);
931 } catch (ParserConfigurationException
| SAXException
| IOException
| TransformerFactoryConfigurationError
| TransformerException e
) {
932 Activator
.logError("Error deleting CustomTxtTraceDefinition: definitionName=" + definitionName
, e
); //$NON-NLS-1$