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