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