tmf: extract common elements in custom txt/xml trace definitions
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / parsers / custom / CustomTxtTraceDefinition.java
1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 * Matthew Khouzam - Add support for default parsers
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.core.parsers.custom;
15
16 import java.io.File;
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;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeSet;
27 import java.util.regex.Pattern;
28 import java.util.regex.PatternSyntaxException;
29
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;
41
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;
50
51 /**
52 * Trace definition for custom text traces.
53 *
54 * @author Patrick Tassé
55 * @since 3.0
56 */
57 public class CustomTxtTraceDefinition extends CustomTraceDefinition {
58
59 /** Input lines */
60 public List<InputLine> inputs;
61
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$
66
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();
74
75 /**
76 * Legacy path to the XML definitions file (in the UI plug-in) TODO Remove
77 * once we feel the transition phase is over.
78 */
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();
83
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 NAME_ATTRIBUTE = Messages.CustomTxtTraceDefinition_name;
87 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT = Messages.CustomTxtTraceDefinition_timestampOutputFormat;
88 private static final String INPUT_LINE_ELEMENT = Messages.CustomTxtTraceDefinition_inputLine;
89 private static final String CARDINALITY_ELEMENT = Messages.CustomTxtTraceDefinition_cardinality;
90 private static final String MIN_ATTRIBUTE = Messages.CustomTxtTraceDefinition_min;
91 private static final String MAX_ATTRIBUTE = Messages.CustomTxtTraceDefinition_max;
92 private static final String REGEX_ELEMENT = Messages.CustomTxtTraceDefinition_regEx;
93 private static final String INPUT_DATA_ELEMENT = Messages.CustomTxtTraceDefinition_inputData;
94 private static final String ACTION_ATTRIBUTE = Messages.CustomTxtTraceDefinition_action;
95 private static final String FORMAT_ATTRIBUTE = Messages.CustomTxtTraceDefinition_format;
96 private static final String OUTPUT_COLUMN_ELEMENT = Messages.CustomTxtTraceDefinition_outputColumn;
97
98 /**
99 * Default constructor.
100 */
101 public CustomTxtTraceDefinition() {
102 this("", new ArrayList<InputLine>(0), new ArrayList<OutputColumn>(0), ""); //$NON-NLS-1$ //$NON-NLS-2$
103 }
104
105 /**
106 * Full constructor.
107 *
108 * @param logtype
109 * Name of the trace type
110 * @param inputs
111 * List of inputs
112 * @param outputs
113 * List of output columns
114 * @param timeStampOutputFormat
115 * The timestamp format to use
116 */
117 public CustomTxtTraceDefinition(String logtype, List<InputLine> inputs,
118 List<OutputColumn> outputs, String timeStampOutputFormat) {
119 this.definitionName = logtype;
120 this.inputs = inputs;
121 this.outputs = outputs;
122 this.timeStampOutputFormat = timeStampOutputFormat;
123 }
124
125 /**
126 * Wrapper to store a line of the log file
127 */
128 public static class InputLine {
129
130 /** Data columns of this line */
131 public List<InputData> columns;
132
133 /** Cardinality of this line (see {@link Cardinality}) */
134 public Cardinality cardinality;
135
136 /** Parent line */
137 public InputLine parentInput;
138
139 /** Level of this line */
140 public int level;
141
142 /** Next input line in the file */
143 public InputLine nextInput;
144
145 /** Children of this line (if one "event" spans many lines) */
146 public List<InputLine> childrenInputs;
147
148 private String regex;
149 private Pattern pattern;
150
151 /**
152 * Default (empty) constructor.
153 */
154 public InputLine() {
155 }
156
157 /**
158 * Constructor.
159 *
160 * @param cardinality
161 * Cardinality of this line.
162 * @param regex
163 * Regex
164 * @param columns
165 * Columns to use
166 */
167 public InputLine(Cardinality cardinality, String regex, List<InputData> columns) {
168 this.cardinality = cardinality;
169 this.regex = regex;
170 this.columns = columns;
171 }
172
173 /**
174 * Set the regex of this input line
175 *
176 * @param regex
177 * Regex to set
178 */
179 public void setRegex(String regex) {
180 this.regex = regex;
181 this.pattern = null;
182 }
183
184 /**
185 * Get the current regex
186 *
187 * @return The current regex
188 */
189 public String getRegex() {
190 return regex;
191 }
192
193 /**
194 * Get the Pattern object of this line's regex
195 *
196 * @return The Pattern
197 * @throws PatternSyntaxException
198 * If the regex does not parse correctly
199 */
200 public Pattern getPattern() throws PatternSyntaxException {
201 if (pattern == null) {
202 pattern = Pattern.compile(regex);
203 }
204 return pattern;
205 }
206
207 /**
208 * Add a child line to this line.
209 *
210 * @param input
211 * The child input line
212 */
213 public void addChild(InputLine input) {
214 if (childrenInputs == null) {
215 childrenInputs = new ArrayList<>(1);
216 } else if (childrenInputs.size() > 0) {
217 InputLine last = childrenInputs.get(childrenInputs.size() - 1);
218 last.nextInput = input;
219 }
220 childrenInputs.add(input);
221 input.parentInput = this;
222 input.level = this.level + 1;
223 }
224
225 /**
226 * Set the next input line.
227 *
228 * @param input
229 * The next input line
230 */
231 public void addNext(InputLine input) {
232 if (parentInput != null) {
233 int index = parentInput.childrenInputs.indexOf(this);
234 parentInput.childrenInputs.add(index + 1, input);
235 InputLine next = nextInput;
236 nextInput = input;
237 input.nextInput = next;
238 }
239 input.parentInput = this.parentInput;
240 input.level = this.level;
241 }
242
243 /**
244 * Move this line up in its parent's children.
245 */
246 public void moveUp() {
247 if (parentInput != null) {
248 int index = parentInput.childrenInputs.indexOf(this);
249 if (index > 0) {
250 parentInput.childrenInputs.add(index - 1, parentInput.childrenInputs.remove(index));
251 parentInput.childrenInputs.get(index).nextInput = nextInput;
252 nextInput = parentInput.childrenInputs.get(index);
253 }
254 }
255 }
256
257 /**
258 * Move this line down in its parent's children.
259 */
260 public void moveDown() {
261 if (parentInput != null) {
262 int index = parentInput.childrenInputs.indexOf(this);
263 if (index < parentInput.childrenInputs.size() - 1) {
264 parentInput.childrenInputs.add(index + 1, parentInput.childrenInputs.remove(index));
265 nextInput = parentInput.childrenInputs.get(index).nextInput;
266 parentInput.childrenInputs.get(index).nextInput = this;
267 }
268 }
269 }
270
271 /**
272 * Add a data column to this line
273 *
274 * @param column
275 * The column to add
276 */
277 public void addColumn(InputData column) {
278 if (columns == null) {
279 columns = new ArrayList<>(1);
280 }
281 columns.add(column);
282 }
283
284 /**
285 * Get the next input lines.
286 *
287 * @param countMap
288 * The map of line "sets".
289 * @return The next list of lines.
290 */
291 public List<InputLine> getNextInputs(Map<InputLine, Integer> countMap) {
292 List<InputLine> nextInputs = new ArrayList<>();
293 InputLine next = nextInput;
294 while (next != null) {
295 nextInputs.add(next);
296 if (next.cardinality.min > 0) {
297 return nextInputs;
298 }
299 next = next.nextInput;
300 }
301 if (parentInput != null && parentInput.level > 0) {
302 int parentCount = countMap.get(parentInput);
303 if (parentCount < parentInput.getMaxCount()) {
304 nextInputs.add(parentInput);
305 }
306 if (parentCount < parentInput.getMinCount()) {
307 return nextInputs;
308 }
309 nextInputs.addAll(parentInput.getNextInputs(countMap));
310 }
311 return nextInputs;
312 }
313
314 /**
315 * Get the minimum possible amount of entries.
316 *
317 * @return The minimum
318 */
319 public int getMinCount() {
320 return cardinality.min;
321 }
322
323 /**
324 * Get the maximum possible amount of entries.
325 *
326 * @return The maximum
327 */
328 public int getMaxCount() {
329 return cardinality.max;
330 }
331
332 @Override
333 public String toString() {
334 return regex + " " + cardinality; //$NON-NLS-1$
335 }
336 }
337
338 /**
339 * Data column for input lines.
340 */
341 public static class InputData {
342
343 /** Name of this column */
344 public String name;
345
346 /** Action id */
347 public int action;
348
349 /** Format */
350 public String format;
351
352 /**
353 * Default (empty) constructor
354 */
355 public InputData() {
356 }
357
358 /**
359 * Full constructor
360 *
361 * @param name
362 * Name
363 * @param action
364 * Action
365 * @param format
366 * Format
367 */
368 public InputData(String name, int action, String format) {
369 this.name = name;
370 this.action = action;
371 this.format = format;
372 }
373
374 /**
375 * Constructor with default format
376 *
377 * @param name
378 * Name
379 * @param action
380 * Action
381 */
382 public InputData(String name, int action) {
383 this.name = name;
384 this.action = action;
385 }
386 }
387
388 /**
389 * Input line cardinality
390 */
391 public static class Cardinality {
392
393 /** Representation of infinity */
394 public final static int INF = Integer.MAX_VALUE;
395
396 /** Preset for [1, 1] */
397 public final static Cardinality ONE = new Cardinality(1, 1);
398
399 /** Preset for [1, inf] */
400 public final static Cardinality ONE_OR_MORE = new Cardinality(1, INF);
401
402 /** Preset for [0, 1] */
403 public final static Cardinality ZERO_OR_ONE = new Cardinality(0, 1);
404
405 /** Preset for [0, inf] */
406 public final static Cardinality ZERO_OR_MORE = new Cardinality(0, INF);
407
408 private final int min;
409 private final int max;
410
411 /**
412 * Constructor.
413 *
414 * @param min
415 * Minimum
416 * @param max
417 * Maximum
418 */
419 public Cardinality(int min, int max) {
420 this.min = min;
421 this.max = max;
422 }
423
424 @Override
425 public String toString() {
426 return "(" + (min >= 0 ? min : "?") + ',' + (max == INF ? "\u221E" : (max >= 0 ? max : "?")) + ')'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
427 }
428
429 @Override
430 public int hashCode() {
431 final int prime = 31;
432 int result = 1;
433 result = prime * result + max;
434 result = prime * result + min;
435 return result;
436 }
437
438 @Override
439 public boolean equals(Object obj) {
440 if (this == obj) {
441 return true;
442 }
443 if (obj == null) {
444 return false;
445 }
446 if (!(obj instanceof Cardinality)) {
447 return false;
448 }
449 Cardinality other = (Cardinality) obj;
450 return (this.min == other.min && this.max == other.max);
451 }
452 }
453
454 @Override
455 public void save() {
456 save(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME);
457 }
458
459 @Override
460 public void save(String path) {
461 try {
462 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
463 DocumentBuilder db = dbf.newDocumentBuilder();
464
465 // The following allows xml parsing without access to the dtd
466 db.setEntityResolver(createEmptyEntityResolver());
467
468 // The following catches xml parsing exceptions
469 db.setErrorHandler(createErrorHandler());
470
471 Document doc = null;
472 File file = new File(path);
473 if (file.canRead()) {
474 doc = db.parse(file);
475 if (!doc.getDocumentElement().getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT)) {
476 return;
477 }
478 } else {
479 doc = db.newDocument();
480 Node node = doc.createElement(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT);
481 doc.appendChild(node);
482 }
483
484 Element root = doc.getDocumentElement();
485
486 NodeList nodeList = root.getChildNodes();
487 for (int i = 0; i < nodeList.getLength(); i++) {
488 Node node = nodeList.item(i);
489 if (node instanceof Element &&
490 node.getNodeName().equals(DEFINITION_ELEMENT) &&
491 definitionName.equals(((Element) node).getAttribute(NAME_ATTRIBUTE))) {
492 root.removeChild(node);
493 }
494 }
495 Element definitionElement = doc.createElement(DEFINITION_ELEMENT);
496 root.appendChild(definitionElement);
497 definitionElement.setAttribute(NAME_ATTRIBUTE, definitionName);
498
499 Element formatElement = doc.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT);
500 definitionElement.appendChild(formatElement);
501 formatElement.appendChild(doc.createTextNode(timeStampOutputFormat));
502
503 if (inputs != null) {
504 for (InputLine inputLine : inputs) {
505 definitionElement.appendChild(createInputLineElement(inputLine, doc));
506 }
507 }
508
509 if (outputs != null) {
510 for (OutputColumn output : outputs) {
511 Element outputColumnElement = doc.createElement(OUTPUT_COLUMN_ELEMENT);
512 definitionElement.appendChild(outputColumnElement);
513 outputColumnElement.setAttribute(NAME_ATTRIBUTE, output.name);
514 }
515 }
516
517 Transformer transformer = TransformerFactory.newInstance().newTransformer();
518 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
519
520 // initialize StreamResult with File object to save to file
521 StreamResult result = new StreamResult(new StringWriter());
522 DOMSource source = new DOMSource(doc);
523 transformer.transform(source, result);
524 String xmlString = result.getWriter().toString();
525
526 try (FileWriter writer = new FileWriter(file);) {
527 writer.write(xmlString);
528 }
529
530 TmfTraceType.addCustomTraceType(TmfTraceType.CUSTOM_TXT_CATEGORY, definitionName);
531
532 } catch (ParserConfigurationException e) {
533 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
534 } catch (TransformerConfigurationException e) {
535 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
536 } catch (TransformerFactoryConfigurationError e) {
537 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
538 } catch (TransformerException e) {
539 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
540 } catch (IOException e) {
541 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
542 } catch (SAXException e) {
543 Activator.logError("Error saving CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
544 }
545 }
546
547 private Element createInputLineElement(InputLine inputLine, Document doc) {
548 Element inputLineElement = doc.createElement(INPUT_LINE_ELEMENT);
549
550 Element cardinalityElement = doc.createElement(CARDINALITY_ELEMENT);
551 inputLineElement.appendChild(cardinalityElement);
552 cardinalityElement.setAttribute(MIN_ATTRIBUTE, Integer.toString(inputLine.cardinality.min));
553 cardinalityElement.setAttribute(MAX_ATTRIBUTE, Integer.toString(inputLine.cardinality.max));
554
555 Element regexElement = doc.createElement(REGEX_ELEMENT);
556 inputLineElement.appendChild(regexElement);
557 regexElement.appendChild(doc.createTextNode(inputLine.regex));
558
559 if (inputLine.columns != null) {
560 for (InputData inputData : inputLine.columns) {
561 Element inputDataElement = doc.createElement(INPUT_DATA_ELEMENT);
562 inputLineElement.appendChild(inputDataElement);
563 inputDataElement.setAttribute(NAME_ATTRIBUTE, inputData.name);
564 inputDataElement.setAttribute(ACTION_ATTRIBUTE, Integer.toString(inputData.action));
565 if (inputData.format != null) {
566 inputDataElement.setAttribute(FORMAT_ATTRIBUTE, inputData.format);
567 }
568 }
569 }
570
571 if (inputLine.childrenInputs != null) {
572 for (InputLine childInputLine : inputLine.childrenInputs) {
573 inputLineElement.appendChild(createInputLineElement(childInputLine, doc));
574 }
575 }
576
577 return inputLineElement;
578 }
579
580 /**
581 * Load the default text trace definitions file.
582 *
583 * @return The loaded trace definitions
584 */
585 public static CustomTxtTraceDefinition[] loadAll() {
586 File defaultFile = new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME);
587 File legacyFile = new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY);
588
589 /*
590 * If there is no file at the expected location, check the legacy
591 * location instead.
592 */
593 if (!defaultFile.exists() && legacyFile.exists()) {
594 CustomTxtTraceDefinition[] oldDefs = loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME_LEGACY);
595 for (CustomTxtTraceDefinition def : oldDefs) {
596 /* Save in the new location */
597 def.save();
598 }
599 }
600
601 Set<CustomTxtTraceDefinition> defs = new TreeSet<>(new Comparator<CustomTxtTraceDefinition>() {
602 @Override
603 public int compare(CustomTxtTraceDefinition o1, CustomTxtTraceDefinition o2) {
604 return o1.definitionName.compareTo(o2.definitionName);
605 }
606 });
607 defs.addAll(Arrays.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME)));
608 defs.addAll(Arrays.asList(loadAll(CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME)));
609 return defs.toArray(new CustomTxtTraceDefinition[0]);
610
611 }
612
613 /**
614 * Load a specific text trace definition file.
615 *
616 * @param path
617 * The path to the file to load
618 * @return The loaded trace definitions
619 */
620 public static CustomTxtTraceDefinition[] loadAll(String path) {
621 try {
622 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
623 DocumentBuilder db = dbf.newDocumentBuilder();
624
625 // The following allows xml parsing without access to the dtd
626 db.setEntityResolver(createEmptyEntityResolver());
627
628 // The following catches xml parsing exceptions
629 db.setErrorHandler(createErrorHandler());
630
631 File file = new File(path);
632 if (!file.canRead()) {
633 return new CustomTxtTraceDefinition[0];
634 }
635 Document doc = db.parse(file);
636
637 Element root = doc.getDocumentElement();
638 if (!root.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT)) {
639 return new CustomTxtTraceDefinition[0];
640 }
641
642 ArrayList<CustomTxtTraceDefinition> defList = new ArrayList<>();
643 NodeList nodeList = root.getChildNodes();
644 for (int i = 0; i < nodeList.getLength(); i++) {
645 Node node = nodeList.item(i);
646 if (node instanceof Element && node.getNodeName().equals(DEFINITION_ELEMENT)) {
647 CustomTxtTraceDefinition def = extractDefinition((Element) node);
648 if (def != null) {
649 defList.add(def);
650 }
651 }
652 }
653 return defList.toArray(new CustomTxtTraceDefinition[0]);
654 } catch (ParserConfigurationException e) {
655 Activator.logError("Error loading all in CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
656 } catch (SAXException e) {
657 Activator.logError("Error loading all in CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
658 } catch (IOException e) {
659 Activator.logError("Error loading all in CustomTxtTraceDefinition: path=" + path, e); //$NON-NLS-1$
660 }
661 return new CustomTxtTraceDefinition[0];
662 }
663
664 /**
665 * Load a single definition.
666 *
667 * @param definitionName
668 * Name of the definition to load
669 * @return The loaded trace definition
670 */
671 public static CustomTxtTraceDefinition load(String definitionName) {
672 try {
673 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
674 DocumentBuilder db = dbf.newDocumentBuilder();
675
676 // The following allows xml parsing without access to the dtd
677 db.setEntityResolver(createEmptyEntityResolver());
678
679 // The following catches xml parsing exceptions
680 db.setErrorHandler(createErrorHandler());
681
682 CustomTxtTraceDefinition value = lookupDefinition(definitionName, db, CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME);
683 if (value == null) {
684 return lookupDefinition(definitionName, db, CUSTOM_TXT_TRACE_DEFINITIONS_DEFAULT_PATH_NAME);
685 }
686 return value;
687 } catch (ParserConfigurationException | SAXException | IOException e) {
688 Activator.logError("Error loading CustomTxtTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
689 }
690 return null;
691 }
692
693 private static CustomTxtTraceDefinition lookupDefinition(String definitionName, DocumentBuilder db, String source) throws SAXException, IOException {
694 File file = new File(source);
695 if (!file.exists()) {
696 return null;
697 }
698 Document doc = db.parse(file);
699
700 Element root = doc.getDocumentElement();
701 if (!root.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT)) {
702 return null;
703 }
704
705 NodeList nodeList = root.getChildNodes();
706 for (int i = 0; i < nodeList.getLength(); i++) {
707 Node node = nodeList.item(i);
708 if (node instanceof Element &&
709 node.getNodeName().equals(DEFINITION_ELEMENT) &&
710 definitionName.equals(((Element) node).getAttribute(NAME_ATTRIBUTE))) {
711 return extractDefinition((Element) node);
712 }
713 }
714 return null;
715 }
716
717 /**
718 * Get the definition from a definition element.
719 *
720 * @param definitionElement
721 * The Element to extract from
722 * @return The loaded trace definition
723 */
724 public static CustomTxtTraceDefinition extractDefinition(Element definitionElement) {
725 CustomTxtTraceDefinition def = new CustomTxtTraceDefinition();
726
727 def.definitionName = definitionElement.getAttribute(NAME_ATTRIBUTE);
728 if (def.definitionName == null) {
729 return null;
730 }
731
732 NodeList nodeList = definitionElement.getChildNodes();
733 for (int i = 0; i < nodeList.getLength(); i++) {
734 Node node = nodeList.item(i);
735 String nodeName = node.getNodeName();
736 if (nodeName.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT)) {
737 Element formatElement = (Element) node;
738 def.timeStampOutputFormat = formatElement.getTextContent();
739 } else if (nodeName.equals(INPUT_LINE_ELEMENT)) {
740 InputLine inputLine = extractInputLine((Element) node);
741 if (inputLine != null) {
742 def.inputs.add(inputLine);
743 }
744 } else if (nodeName.equals(OUTPUT_COLUMN_ELEMENT)) {
745 Element outputColumnElement = (Element) node;
746 OutputColumn outputColumn = new OutputColumn();
747 outputColumn.name = outputColumnElement.getAttribute(NAME_ATTRIBUTE);
748 def.outputs.add(outputColumn);
749 }
750 }
751 return def;
752 }
753
754 private static InputLine extractInputLine(Element inputLineElement) {
755 InputLine inputLine = new InputLine();
756 NodeList nodeList = inputLineElement.getChildNodes();
757 for (int i = 0; i < nodeList.getLength(); i++) {
758 Node node = nodeList.item(i);
759 String nodeName = node.getNodeName();
760 if (nodeName.equals(CARDINALITY_ELEMENT)) {
761 Element cardinalityElement = (Element) node;
762 try {
763 int min = Integer.parseInt(cardinalityElement.getAttribute(MIN_ATTRIBUTE));
764 int max = Integer.parseInt(cardinalityElement.getAttribute(MAX_ATTRIBUTE));
765 inputLine.cardinality = new Cardinality(min, max);
766 } catch (NumberFormatException e) {
767 return null;
768 }
769 } else if (nodeName.equals(REGEX_ELEMENT)) {
770 Element regexElement = (Element) node;
771 inputLine.regex = regexElement.getTextContent();
772 } else if (nodeName.equals(INPUT_DATA_ELEMENT)) {
773 Element inputDataElement = (Element) node;
774 InputData inputData = new InputData();
775 inputData.name = inputDataElement.getAttribute(NAME_ATTRIBUTE);
776 inputData.action = Integer.parseInt(inputDataElement.getAttribute(ACTION_ATTRIBUTE));
777 inputData.format = inputDataElement.getAttribute(FORMAT_ATTRIBUTE);
778 inputLine.addColumn(inputData);
779 } else if (nodeName.equals(INPUT_LINE_ELEMENT)) {
780 Element childInputLineElement = (Element) node;
781 InputLine childInputLine = extractInputLine(childInputLineElement);
782 if (childInputLine != null) {
783 inputLine.addChild(childInputLine);
784 }
785 }
786 }
787 return inputLine;
788 }
789
790 /**
791 * Delete a definition from the currently loaded ones.
792 *
793 * @param definitionName
794 * The name of the definition to delete
795 */
796 public static void delete(String definitionName) {
797 try {
798 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
799 DocumentBuilder db = dbf.newDocumentBuilder();
800
801 // The following allows xml parsing without access to the dtd
802 db.setEntityResolver(createEmptyEntityResolver());
803
804 // The following catches xml parsing exceptions
805 db.setErrorHandler(createErrorHandler());
806
807 File file = new File(CUSTOM_TXT_TRACE_DEFINITIONS_PATH_NAME);
808 Document doc = db.parse(file);
809
810 Element root = doc.getDocumentElement();
811 if (!root.getNodeName().equals(CUSTOM_TXT_TRACE_DEFINITION_ROOT_ELEMENT)) {
812 return;
813 }
814
815 NodeList nodeList = root.getChildNodes();
816 for (int i = 0; i < nodeList.getLength(); i++) {
817 Node node = nodeList.item(i);
818 if (node instanceof Element &&
819 node.getNodeName().equals(DEFINITION_ELEMENT) &&
820 definitionName.equals(((Element) node).getAttribute(NAME_ATTRIBUTE))) {
821 root.removeChild(node);
822 }
823 }
824
825 Transformer transformer = TransformerFactory.newInstance().newTransformer();
826 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
827
828 // initialize StreamResult with File object to save to file
829 StreamResult result = new StreamResult(new StringWriter());
830 DOMSource source = new DOMSource(doc);
831 transformer.transform(source, result);
832 String xmlString = result.getWriter().toString();
833
834 try (FileWriter writer = new FileWriter(file);) {
835 writer.write(xmlString);
836 }
837
838 TmfTraceType.removeCustomTraceType(TmfTraceType.CUSTOM_TXT_CATEGORY, definitionName);
839 // Check if default definition needs to be reloaded
840 TmfTraceType.addCustomTraceType(TmfTraceType.CUSTOM_TXT_CATEGORY, definitionName);
841
842 } catch (ParserConfigurationException | SAXException | IOException | TransformerFactoryConfigurationError | TransformerException e) {
843 Activator.logError("Error deleting CustomTxtTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
844 }
845 }
846 }
This page took 0.051406 seconds and 5 git commands to generate.