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