tmf: Add extension point to add custom trace types to plugins
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / parsers / custom / CustomXmlTraceDefinition.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
70b7bc9c 11 * Matthew Khouzam - Add support for default xml parsers
be222f56
PT
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.core.parsers.custom;
be222f56
PT
15
16import java.io.ByteArrayInputStream;
17import java.io.File;
1d8ab692 18import java.io.FileInputStream;
be222f56
PT
19import java.io.FileWriter;
20import java.io.IOException;
1d8ab692 21import java.io.InputStream;
be222f56
PT
22import java.io.StringWriter;
23import java.util.ArrayList;
70b7bc9c 24import java.util.Arrays;
fa941de8 25import java.util.Collection;
70b7bc9c 26import java.util.Comparator;
be222f56 27import java.util.List;
f5cc6ed1 28import java.util.Map.Entry;
70b7bc9c
MK
29import java.util.Set;
30import java.util.TreeSet;
be222f56
PT
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
70b7bc9c 43import org.eclipse.core.runtime.Platform;
f5cc6ed1 44import org.eclipse.jdt.annotation.NonNull;
2bdf0193
AM
45import org.eclipse.tracecompass.internal.tmf.core.Activator;
46import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
be222f56
PT
47import org.w3c.dom.Document;
48import org.w3c.dom.Element;
49import org.w3c.dom.Node;
50import org.w3c.dom.NodeList;
51import org.xml.sax.EntityResolver;
52import org.xml.sax.ErrorHandler;
53import org.xml.sax.InputSource;
54import org.xml.sax.SAXException;
55import org.xml.sax.SAXParseException;
56
a0a88f65
AM
57/**
58 * Trace definition for custom XML traces.
59 *
60 * @author Patrick Tassé
61 */
be222f56
PT
62public class CustomXmlTraceDefinition extends CustomTraceDefinition {
63
f5cc6ed1 64 /** Ignore tag
a36fa387 65 * @deprecated Use {@link org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition.Tag#IGNORE} instead. */
f5cc6ed1 66 @Deprecated
a0a88f65
AM
67 public static final String TAG_IGNORE = Messages.CustomXmlTraceDefinition_ignoreTag;
68
c9b31f60
BH
69 /**
70 * Custom XML label used internally and therefore should not be externalized
71 */
72 public static final String CUSTOM_XML_CATEGORY = "Custom XML"; //$NON-NLS-1$
73
74
70b7bc9c
MK
75 /** Name of the default XML definitions file */
76 protected static final String CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_FILE_NAME = "custom_xml_default_parsers.xml"; //$NON-NLS-1$
77
a0a88f65 78 /** Name of the XML definitions file */
be222f56 79 protected static final String CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME = "custom_xml_parsers.xml"; //$NON-NLS-1$
a0a88f65 80
70b7bc9c
MK
81 /** Path to the XML definitions file */
82 protected static final String CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME =
cb1cf0e8
MK
83 Platform.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
84 CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_FILE_NAME;
70b7bc9c 85
a0a88f65 86 /** Path to the XML definitions file */
be222f56 87 protected static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME =
70b7bc9c 88 Activator.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
be222f56 89
cb1cf0e8 90 /**
c9b31f60 91 * Legacy path to the XML definitions file (in the UI plug-in of linux tools) TODO Remove
cb1cf0e8
MK
92 * once we feel the transition phase is over.
93 */
c9b31f60 94 private static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI =
03573754
AM
95 Activator.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
96 .append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
97 .append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
98
c9b31f60
BH
99 /**
100 * Legacy path to the XML definitions file (in the core plug-in of linux tools) TODO Remove
101 * once we feel the transition phase is over.
102 */
103 private static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE =
104 Activator.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
105 .append("org.eclipse.linuxtools.tmf.core") //$NON-NLS-1$
106 .append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
107
332527a4 108 // TODO: These strings should not be externalized
be222f56
PT
109 private static final String CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT = Messages.CustomXmlTraceDefinition_definitionRootElement;
110 private static final String DEFINITION_ELEMENT = Messages.CustomXmlTraceDefinition_definition;
332527a4 111 private static final String CATEGORY_ATTRIBUTE = Messages.CustomXmlTraceDefinition_category;
f5cc6ed1 112 private static final String TAG_ATTRIBUTE = Messages.CustomXmlTraceDefinition_tag;
be222f56
PT
113 private static final String NAME_ATTRIBUTE = Messages.CustomXmlTraceDefinition_name;
114 private static final String LOG_ENTRY_ATTRIBUTE = Messages.CustomXmlTraceDefinition_logEntry;
eddf2682 115 private static final String EVENT_TYPE_ATTRIBUTE = Messages.CustomXmlTraceDefinition_eventType;
be222f56
PT
116 private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT = Messages.CustomXmlTraceDefinition_timestampOutputFormat;
117 private static final String INPUT_ELEMENT_ELEMENT = Messages.CustomXmlTraceDefinition_inputElement;
118 private static final String ATTRIBUTE_ELEMENT = Messages.CustomXmlTraceDefinition_attribute;
119 private static final String INPUT_DATA_ELEMENT = Messages.CustomXmlTraceDefinition_inputData;
120 private static final String ACTION_ATTRIBUTE = Messages.CustomXmlTraceDefinition_action;
121 private static final String FORMAT_ATTRIBUTE = Messages.CustomXmlTraceDefinition_format;
122 private static final String OUTPUT_COLUMN_ELEMENT = Messages.CustomXmlTraceDefinition_outputColumn;
123
fa941de8
MAL
124 /**
125 * This is the value that the extension sets for traceContentType to be able
126 * to load an XML parser
127 **/
128 private static final String TRACE_CONTENT_TYPE_ATTRIBUTE_VALUE = "xml"; //$NON-NLS-1$
129
a0a88f65 130 /** Top-level input element */
a7418109 131 public CustomXmlInputElement rootInputElement;
be222f56 132
a0a88f65
AM
133 /**
134 * Default constructor
135 */
be222f56 136 public CustomXmlTraceDefinition() {
c9b31f60 137 this(CUSTOM_XML_CATEGORY, "", null, new ArrayList<OutputColumn>(), ""); //$NON-NLS-1$ //$NON-NLS-2$
be222f56
PT
138 }
139
332527a4
PT
140 /**
141 * Full constructor
142 *
143 * @param category
144 * Category of the trace type
145 * @param traceType
146 * Name of the trace type
147 * @param rootElement
148 * The top-level XML element
149 * @param outputs
150 * The list of output columns
151 * @param timeStampOutputFormat
152 * The timestamp format to use
332527a4 153 */
a7418109 154 public CustomXmlTraceDefinition(String category, String traceType, CustomXmlInputElement rootElement,
332527a4
PT
155 List<OutputColumn> outputs, String timeStampOutputFormat) {
156 this.categoryName = category;
157 this.definitionName = traceType;
be222f56
PT
158 this.rootInputElement = rootElement;
159 this.outputs = outputs;
160 this.timeStampOutputFormat = timeStampOutputFormat;
161 }
162
a0a88f65 163 @Override
be222f56
PT
164 public void save() {
165 save(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
166 }
167
70b7bc9c 168 @Override
be222f56
PT
169 public void save(String path) {
170 try {
171 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
172 DocumentBuilder db = dbf.newDocumentBuilder();
173
174 // The following allows xml parsing without access to the dtd
cb1cf0e8 175 db.setEntityResolver(createEmptyEntityResolver());
be222f56
PT
176
177 // The following catches xml parsing exceptions
cb1cf0e8 178 db.setErrorHandler(createErrorHandler());
be222f56
PT
179
180 Document doc = null;
181 File file = new File(path);
182 if (file.canRead()) {
183 doc = db.parse(file);
70b7bc9c 184 if (!doc.getDocumentElement().getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
d1b0903f 185 Activator.logError(String.format("Error saving CustomXmlTraceDefinition: path=%s is not a valid custom parser file", path)); //$NON-NLS-1$
be222f56
PT
186 return;
187 }
188 } else {
189 doc = db.newDocument();
190 Node node = doc.createElement(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT);
191 doc.appendChild(node);
192 }
193
194 Element root = doc.getDocumentElement();
195
332527a4
PT
196 Element oldDefinitionElement = findDefinitionElement(root, categoryName, definitionName);
197 if (oldDefinitionElement != null) {
198 root.removeChild(oldDefinitionElement);
be222f56
PT
199 }
200 Element definitionElement = doc.createElement(DEFINITION_ELEMENT);
201 root.appendChild(definitionElement);
332527a4 202 definitionElement.setAttribute(CATEGORY_ATTRIBUTE, categoryName);
be222f56
PT
203 definitionElement.setAttribute(NAME_ATTRIBUTE, definitionName);
204
4d12b563
PT
205 if (timeStampOutputFormat != null && !timeStampOutputFormat.isEmpty()) {
206 Element formatElement = doc.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT);
207 definitionElement.appendChild(formatElement);
208 formatElement.appendChild(doc.createTextNode(timeStampOutputFormat));
209 }
be222f56
PT
210
211 if (rootInputElement != null) {
212 definitionElement.appendChild(createInputElementElement(rootInputElement, doc));
213 }
214
215 if (outputs != null) {
216 for (OutputColumn output : outputs) {
217 Element outputColumnElement = doc.createElement(OUTPUT_COLUMN_ELEMENT);
218 definitionElement.appendChild(outputColumnElement);
f5cc6ed1 219 outputColumnElement.setAttribute(TAG_ATTRIBUTE, output.tag.name());
be222f56
PT
220 outputColumnElement.setAttribute(NAME_ATTRIBUTE, output.name);
221 }
222 }
223
224 Transformer transformer = TransformerFactory.newInstance().newTransformer();
225 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
226
70b7bc9c 227 // initialize StreamResult with File object to save to file
be222f56
PT
228 StreamResult result = new StreamResult(new StringWriter());
229 DOMSource source = new DOMSource(doc);
230 transformer.transform(source, result);
231 String xmlString = result.getWriter().toString();
232
507b1336
AM
233 try (FileWriter writer = new FileWriter(file);) {
234 writer.write(xmlString);
235 }
52885aeb 236
4b3b667b 237 TmfTraceType.addCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
52885aeb 238
cb1cf0e8 239 } catch (ParserConfigurationException | TransformerFactoryConfigurationError | TransformerException | IOException | SAXException e) {
47aafe74 240 Activator.logError("Error saving CustomXmlTraceDefinition: path=" + path, e); //$NON-NLS-1$
be222f56
PT
241 }
242 }
243
a7418109 244 private Element createInputElementElement(CustomXmlInputElement inputElement, Document doc) {
be222f56 245 Element inputElementElement = doc.createElement(INPUT_ELEMENT_ELEMENT);
a7418109 246 inputElementElement.setAttribute(NAME_ATTRIBUTE, inputElement.getElementName());
be222f56 247
a7418109
MK
248 if (inputElement.isLogEntry()) {
249 inputElementElement.setAttribute(LOG_ENTRY_ATTRIBUTE, Boolean.toString(inputElement.isLogEntry()));
be222f56
PT
250 }
251
eddf2682
PT
252 if (inputElement.getEventType() != null) {
253 inputElementElement.setAttribute(EVENT_TYPE_ATTRIBUTE, inputElement.getEventType());
254 }
255
a7418109 256 if (inputElement.getParentElement() != null) {
be222f56
PT
257 Element inputDataElement = doc.createElement(INPUT_DATA_ELEMENT);
258 inputElementElement.appendChild(inputDataElement);
f5cc6ed1 259 inputDataElement.setAttribute(TAG_ATTRIBUTE, inputElement.getInputTag().name());
a7418109
MK
260 inputDataElement.setAttribute(NAME_ATTRIBUTE, inputElement.getInputName());
261 inputDataElement.setAttribute(ACTION_ATTRIBUTE, Integer.toString(inputElement.getInputAction()));
f5cc6ed1
PT
262 String inputFormat = inputElement.getInputFormat();
263 if (inputFormat != null && !inputFormat.isEmpty()) {
264 inputDataElement.setAttribute(FORMAT_ATTRIBUTE, inputFormat);
be222f56
PT
265 }
266 }
267
a7418109
MK
268 if (inputElement.getAttributes() != null) {
269 for (CustomXmlInputAttribute attribute : inputElement.getAttributes()) {
be222f56
PT
270 Element inputAttributeElement = doc.createElement(ATTRIBUTE_ELEMENT);
271 inputElementElement.appendChild(inputAttributeElement);
a7418109 272 inputAttributeElement.setAttribute(NAME_ATTRIBUTE, attribute.getAttributeName());
be222f56
PT
273 Element inputDataElement = doc.createElement(INPUT_DATA_ELEMENT);
274 inputAttributeElement.appendChild(inputDataElement);
f5cc6ed1 275 inputDataElement.setAttribute(TAG_ATTRIBUTE, attribute.getInputTag().name());
a7418109
MK
276 inputDataElement.setAttribute(NAME_ATTRIBUTE, attribute.getInputName());
277 inputDataElement.setAttribute(ACTION_ATTRIBUTE, Integer.toString(attribute.getInputAction()));
f5cc6ed1
PT
278 String inputFormat = attribute.getInputFormat();
279 if (inputFormat != null && !inputFormat.isEmpty()) {
280 inputDataElement.setAttribute(FORMAT_ATTRIBUTE, inputFormat);
be222f56
PT
281 }
282 }
283 }
284
a7418109
MK
285 if (inputElement.getChildElements() != null) {
286 for (CustomXmlInputElement childInputElement : inputElement.getChildElements()) {
be222f56
PT
287 inputElementElement.appendChild(createInputElementElement(childInputElement, doc));
288 }
289 }
290
291 return inputElementElement;
292 }
293
a0a88f65 294 /**
54af96ab
PT
295 * Load all custom XML trace definitions, including the user-defined and
296 * default (built-in) parsers.
a0a88f65
AM
297 *
298 * @return The loaded trace definitions
299 */
be222f56 300 public static CustomXmlTraceDefinition[] loadAll() {
54af96ab
PT
301 return loadAll(true);
302 }
303
304 /**
305 * Load all custom XML trace definitions, including the user-defined and,
306 * optionally, the default (built-in) parsers.
307 *
308 * @param includeDefaults
309 * if true, the default (built-in) parsers are included
310 *
311 * @return The loaded trace definitions
54af96ab
PT
312 */
313 public static CustomXmlTraceDefinition[] loadAll(boolean includeDefaults) {
03573754 314 File defaultFile = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
c9b31f60
BH
315 File legacyFileUI = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI);
316 File legacyFileCore = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE);
03573754
AM
317
318 /*
319 * If there is no file at the expected location, check the legacy
c9b31f60 320 * locations instead.
03573754 321 */
c9b31f60
BH
322 if (!defaultFile.exists()) {
323 if (legacyFileCore.exists()) {
324 transferDefinitions(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE);
325 } else if (legacyFileUI.exists()) {
326 transferDefinitions(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI);
03573754
AM
327 }
328 }
329
70b7bc9c 330 Set<CustomXmlTraceDefinition> defs = new TreeSet<>(new Comparator<CustomXmlTraceDefinition>() {
70b7bc9c
MK
331 @Override
332 public int compare(CustomXmlTraceDefinition o1, CustomXmlTraceDefinition o2) {
c22ca172
PT
333 int result = o1.categoryName.compareTo(o2.categoryName);
334 if (result != 0) {
335 return result;
336 }
70b7bc9c
MK
337 return o1.definitionName.compareTo(o2.definitionName);
338 }
339 });
340 defs.addAll(Arrays.asList(loadAll(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME)));
54af96ab
PT
341 if (includeDefaults) {
342 defs.addAll(Arrays.asList(loadAll(CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME)));
fa941de8
MAL
343
344 // Also load definitions contributed by extensions
345 Collection<String> paths = getExtensionDefinitionsPaths(TRACE_CONTENT_TYPE_ATTRIBUTE_VALUE);
346 for (String customTraceDefinitionPath : paths) {
347 defs.addAll(Arrays.asList(loadAll(customTraceDefinitionPath)));
348 }
54af96ab 349 }
70b7bc9c 350 return defs.toArray(new CustomXmlTraceDefinition[0]);
be222f56
PT
351 }
352
c9b31f60
BH
353 private static void transferDefinitions(String defFile) {
354 CustomXmlTraceDefinition[] oldDefs = loadAll(defFile);
355 for (CustomXmlTraceDefinition def : oldDefs) {
356 /* Save in the new location */
357 def.save();
358 }
359 }
360
361
a0a88f65
AM
362 /**
363 * Load all the XML trace definitions in the given definitions file.
364 *
365 * @param path
366 * Path to the definitions file to load
367 * @return The loaded trace definitions
368 */
be222f56 369 public static CustomXmlTraceDefinition[] loadAll(String path) {
1d8ab692
GB
370 File file = new File(path);
371 if (!file.canRead()) {
372 return new CustomXmlTraceDefinition[0];
373 }
374 try (FileInputStream fis = new FileInputStream(file);) {
375 return loadAll(fis);
376 } catch (IOException e) {
377 Activator.logError("Error loading all in CustomXmlTraceDefinition: path=" + path, e); //$NON-NLS-1$
378 }
379 return new CustomXmlTraceDefinition[0];
380 }
381
382 /**
383 * Load all the XML trace definitions from the given stream
384 *
385 * @param stream
386 * An input stream from which to read the definitions
387 * @return The loaded trace definitions
1d8ab692
GB
388 */
389 public static CustomXmlTraceDefinition[] loadAll(InputStream stream) {
be222f56
PT
390 try {
391 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
392 DocumentBuilder db = dbf.newDocumentBuilder();
393
394 // The following allows xml parsing without access to the dtd
cb1cf0e8 395 db.setEntityResolver(createEmptyEntityResolver());
be222f56
PT
396
397 // The following catches xml parsing exceptions
cb1cf0e8 398 db.setErrorHandler(createErrorHandler());
be222f56 399
1d8ab692 400 Document doc = db.parse(stream);
be222f56 401 Element root = doc.getDocumentElement();
70b7bc9c 402 if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
be222f56
PT
403 return new CustomXmlTraceDefinition[0];
404 }
405
507b1336 406 ArrayList<CustomXmlTraceDefinition> defList = new ArrayList<>();
be222f56
PT
407 NodeList nodeList = root.getChildNodes();
408 for (int i = 0; i < nodeList.getLength(); i++) {
409 Node node = nodeList.item(i);
410 if (node instanceof Element && node.getNodeName().equals(DEFINITION_ELEMENT)) {
411 CustomXmlTraceDefinition def = extractDefinition((Element) node);
412 if (def != null) {
413 defList.add(def);
414 }
415 }
416 }
417 return defList.toArray(new CustomXmlTraceDefinition[0]);
cb1cf0e8 418 } catch (ParserConfigurationException | SAXException | IOException e) {
1d8ab692 419 Activator.logError("Error loading all in CustomXmlTraceDefinition: path=" + stream, e); //$NON-NLS-1$
be222f56
PT
420 }
421 return new CustomXmlTraceDefinition[0];
422 }
423
332527a4
PT
424 /**
425 * Load the given trace definition.
426 *
427 * @param categoryName
428 * Category of the definition to load
429 * @param definitionName
430 * Name of the XML trace definition to load
431 * @return The loaded trace definition
332527a4
PT
432 */
433 public static CustomXmlTraceDefinition load(String categoryName, String definitionName) {
be222f56
PT
434 try {
435 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
436 DocumentBuilder db = dbf.newDocumentBuilder();
437
438 // The following allows xml parsing without access to the dtd
a0a88f65 439 EntityResolver resolver = new EntityResolver() {
be222f56 440 @Override
a0a88f65 441 public InputSource resolveEntity(String publicId, String systemId) {
be222f56
PT
442 String empty = ""; //$NON-NLS-1$
443 ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
444 return new InputSource(bais);
445 }
446 };
447 db.setEntityResolver(resolver);
448
449 // The following catches xml parsing exceptions
a0a88f65 450 db.setErrorHandler(new ErrorHandler() {
be222f56 451 @Override
70b7bc9c
MK
452 public void error(SAXParseException saxparseexception) throws SAXException {
453 }
a0a88f65 454
be222f56 455 @Override
70b7bc9c
MK
456 public void warning(SAXParseException saxparseexception) throws SAXException {
457 }
a0a88f65 458
be222f56 459 @Override
a0a88f65 460 public void fatalError(SAXParseException saxparseexception) throws SAXException {
be222f56 461 throw saxparseexception;
a0a88f65
AM
462 }
463 });
be222f56 464
332527a4 465 CustomXmlTraceDefinition value = lookupXmlDefinition(categoryName, definitionName, db, CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
70b7bc9c 466 if (value == null) {
332527a4 467 value = lookupXmlDefinition(categoryName, definitionName, db, CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME);
be222f56 468 }
70b7bc9c 469 return value;
cb1cf0e8 470 } catch (ParserConfigurationException | SAXException | IOException e) {
47aafe74 471 Activator.logError("Error loading CustomXmlTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
be222f56
PT
472 }
473 return null;
474 }
475
332527a4 476 private static CustomXmlTraceDefinition lookupXmlDefinition(String categoryName, String definitionName, DocumentBuilder db, String source) throws SAXException, IOException {
70b7bc9c
MK
477 File file = new File(source);
478 if (!file.exists()) {
479 return null;
480 }
481
482 Document doc = db.parse(file);
483
484 Element root = doc.getDocumentElement();
485 if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
486 return null;
487 }
488
332527a4
PT
489 Element definitionElement = findDefinitionElement(root, categoryName, definitionName);
490 if (definitionElement != null) {
491 return extractDefinition(definitionElement);
492 }
493 return null;
494 }
495
496 private static Element findDefinitionElement(Element root, String categoryName, String definitionName) {
70b7bc9c
MK
497 NodeList nodeList = root.getChildNodes();
498 for (int i = 0; i < nodeList.getLength(); i++) {
499 Node node = nodeList.item(i);
332527a4
PT
500 if (node instanceof Element && node.getNodeName().equals(DEFINITION_ELEMENT)) {
501 Element element = (Element) node;
502 String categoryAttribute = element.getAttribute(CATEGORY_ATTRIBUTE);
503 if (categoryAttribute.isEmpty()) {
c9b31f60 504 categoryAttribute = CUSTOM_XML_CATEGORY;
332527a4
PT
505 }
506 String nameAttribute = element.getAttribute(NAME_ATTRIBUTE);
507 if (categoryName.equals(categoryAttribute) &&
508 definitionName.equals(nameAttribute)) {
509 return element;
510 }
70b7bc9c
MK
511 }
512 }
513 return null;
514 }
515
a0a88f65
AM
516 /**
517 * Extract a trace definition from an XML element.
518 *
519 * @param definitionElement
520 * Definition element
521 * @return The extracted trace definition
522 */
be222f56
PT
523 public static CustomXmlTraceDefinition extractDefinition(Element definitionElement) {
524 CustomXmlTraceDefinition def = new CustomXmlTraceDefinition();
525
332527a4
PT
526 def.categoryName = definitionElement.getAttribute(CATEGORY_ATTRIBUTE);
527 if (def.categoryName.isEmpty()) {
c9b31f60 528 def.categoryName = CUSTOM_XML_CATEGORY;
332527a4 529 }
be222f56 530 def.definitionName = definitionElement.getAttribute(NAME_ATTRIBUTE);
332527a4 531 if (def.definitionName.isEmpty()) {
be222f56
PT
532 return null;
533 }
534
535 NodeList nodeList = definitionElement.getChildNodes();
536 for (int i = 0; i < nodeList.getLength(); i++) {
537 Node node = nodeList.item(i);
538 String nodeName = node.getNodeName();
539 if (nodeName.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT)) {
540 Element formatElement = (Element) node;
541 def.timeStampOutputFormat = formatElement.getTextContent();
542 } else if (nodeName.equals(INPUT_ELEMENT_ELEMENT)) {
a7418109 543 CustomXmlInputElement inputElement = extractInputElement((Element) node);
be222f56
PT
544 if (inputElement != null) {
545 if (def.rootInputElement == null) {
546 def.rootInputElement = inputElement;
547 } else {
548 return null;
549 }
550 }
551 } else if (nodeName.equals(OUTPUT_COLUMN_ELEMENT)) {
552 Element outputColumnElement = (Element) node;
f5cc6ed1
PT
553 Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(outputColumnElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
554 OutputColumn outputColumn = new OutputColumn(entry.getKey(), entry.getValue());
be222f56
PT
555 def.outputs.add(outputColumn);
556 }
557 }
558 return def;
559 }
560
a7418109
MK
561 private static CustomXmlInputElement extractInputElement(Element inputElementElement) {
562 CustomXmlInputElement inputElement = new CustomXmlInputElement();
563 inputElement.setElementName(inputElementElement.getAttribute(NAME_ATTRIBUTE));
564 inputElement.setLogEntry((Boolean.toString(true).equals(inputElementElement.getAttribute(LOG_ENTRY_ATTRIBUTE))) ? true : false);
eddf2682
PT
565 String eventType = inputElementElement.getAttribute(EVENT_TYPE_ATTRIBUTE);
566 inputElement.setEventType(eventType.isEmpty() ? null : eventType);
be222f56
PT
567 NodeList nodeList = inputElementElement.getChildNodes();
568 for (int i = 0; i < nodeList.getLength(); i++) {
569 Node node = nodeList.item(i);
570 String nodeName = node.getNodeName();
571 if (nodeName.equals(INPUT_DATA_ELEMENT)) {
572 Element inputDataElement = (Element) node;
f5cc6ed1
PT
573 Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(inputDataElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
574 inputElement.setInputTag(entry.getKey());
575 inputElement.setInputName(entry.getValue());
a7418109
MK
576 inputElement.setInputAction(Integer.parseInt(inputDataElement.getAttribute(ACTION_ATTRIBUTE)));
577 inputElement.setInputFormat(inputDataElement.getAttribute(FORMAT_ATTRIBUTE));
be222f56
PT
578 } else if (nodeName.equals(ATTRIBUTE_ELEMENT)) {
579 Element attributeElement = (Element) node;
a7418109
MK
580
581 String attributeName = attributeElement.getAttribute(NAME_ATTRIBUTE);
be222f56
PT
582 NodeList attributeNodeList = attributeElement.getChildNodes();
583 for (int j = 0; j < attributeNodeList.getLength(); j++) {
584 Node attributeNode = attributeNodeList.item(j);
585 String attributeNodeName = attributeNode.getNodeName();
586 if (attributeNodeName.equals(INPUT_DATA_ELEMENT)) {
587 Element inputDataElement = (Element) attributeNode;
f5cc6ed1
PT
588 Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(inputDataElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
589 int action = Integer.parseInt(inputDataElement.getAttribute(ACTION_ATTRIBUTE));
590 String format = inputDataElement.getAttribute(FORMAT_ATTRIBUTE);
591 inputElement.addAttribute(new CustomXmlInputAttribute(attributeName, entry.getKey(), entry.getValue(), action, format));
592 break;
be222f56
PT
593 }
594 }
be222f56
PT
595 } else if (nodeName.equals(INPUT_ELEMENT_ELEMENT)) {
596 Element childInputElementElement = (Element) node;
a7418109 597 CustomXmlInputElement childInputElement = extractInputElement(childInputElementElement);
be222f56
PT
598 if (childInputElement != null) {
599 inputElement.addChild(childInputElement);
600 }
601 }
602 }
603 return inputElement;
604 }
605
332527a4
PT
606 /**
607 * Delete a definition from the currently loaded ones.
608 *
609 * @param categoryName
610 * The category of the definition to delete
611 * @param definitionName
612 * The name of the definition to delete
332527a4
PT
613 */
614 public static void delete(String categoryName, String definitionName) {
be222f56
PT
615 try {
616 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
617 DocumentBuilder db = dbf.newDocumentBuilder();
618
619 // The following allows xml parsing without access to the dtd
a0a88f65 620 EntityResolver resolver = new EntityResolver() {
be222f56 621 @Override
a0a88f65 622 public InputSource resolveEntity(String publicId, String systemId) {
be222f56
PT
623 String empty = ""; //$NON-NLS-1$
624 ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
625 return new InputSource(bais);
626 }
627 };
628 db.setEntityResolver(resolver);
629
630 // The following catches xml parsing exceptions
a0a88f65 631 db.setErrorHandler(new ErrorHandler() {
be222f56 632 @Override
70b7bc9c
MK
633 public void error(SAXParseException saxparseexception) throws SAXException {
634 }
a0a88f65 635
be222f56 636 @Override
70b7bc9c
MK
637 public void warning(SAXParseException saxparseexception) throws SAXException {
638 }
a0a88f65 639
be222f56 640 @Override
a0a88f65 641 public void fatalError(SAXParseException saxparseexception) throws SAXException {
be222f56 642 throw saxparseexception;
a0a88f65
AM
643 }
644 });
be222f56
PT
645
646 File file = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
647 Document doc = db.parse(file);
648
649 Element root = doc.getDocumentElement();
70b7bc9c 650 if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
be222f56
PT
651 return;
652 }
653
332527a4
PT
654 Element definitionElement = findDefinitionElement(root, categoryName, definitionName);
655 if (definitionElement != null) {
656 root.removeChild(definitionElement);
be222f56
PT
657 }
658
659 Transformer transformer = TransformerFactory.newInstance().newTransformer();
660 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
661
70b7bc9c 662 // initialize StreamResult with File object to save to file
be222f56
PT
663 StreamResult result = new StreamResult(new StringWriter());
664 DOMSource source = new DOMSource(doc);
665 transformer.transform(source, result);
666 String xmlString = result.getWriter().toString();
667
507b1336
AM
668 try (FileWriter writer = new FileWriter(file);) {
669 writer.write(xmlString);
670 }
52885aeb 671
4b3b667b 672 TmfTraceType.removeCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
0621dbae 673 // Check if default definition needs to be reloaded
4b3b667b 674 TmfTraceType.addCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
52885aeb 675
cb1cf0e8 676 } catch (ParserConfigurationException | SAXException | IOException | TransformerFactoryConfigurationError | TransformerException e) {
47aafe74 677 Activator.logError("Error deleteing CustomXmlTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
be222f56
PT
678 }
679 }
680}
This page took 0.126296 seconds and 5 git commands to generate.