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