blob: bbe4758cf5f8775bb9f8e757b88b0cc6b3bf776c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Patrick Tasse - Initial API and implementation
* Matthew Khouzam - Add support for default xml parsers
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.parsers.custom;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.common.core.xml.XmlUtils;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Trace definition for custom XML traces.
*
* @author Patrick Tassé
*/
public class CustomXmlTraceDefinition extends CustomTraceDefinition {
/**
* Custom XML label used internally and therefore should not be externalized
*/
public static final String CUSTOM_XML_CATEGORY = "Custom XML"; //$NON-NLS-1$
/** Name of the default XML definitions file */
protected static final String CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_FILE_NAME = "custom_xml_default_parsers.xml"; //$NON-NLS-1$
/** Name of the XML definitions file */
protected static final String CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME = "custom_xml_parsers.xml"; //$NON-NLS-1$
/** Path to the XML definitions file */
protected static final String CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME =
Platform.getInstallLocation().getURL().getPath() + "templates/org.eclipse.linuxtools.tmf.core/" + //$NON-NLS-1$
CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_FILE_NAME;
/** Path to the XML definitions file */
protected static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME =
Activator.getDefault().getStateLocation().addTrailingSeparator().append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
/**
* Legacy path to the XML definitions file (in the UI plug-in of linux tools) TODO Remove
* once we feel the transition phase is over.
*/
private static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI =
Activator.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
.append("org.eclipse.linuxtools.tmf.ui") //$NON-NLS-1$
.append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
/**
* Legacy path to the XML definitions file (in the core plug-in of linux tools) TODO Remove
* once we feel the transition phase is over.
*/
private static final String CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE =
Activator.getDefault().getStateLocation().removeLastSegments(1).addTrailingSeparator()
.append("org.eclipse.linuxtools.tmf.core") //$NON-NLS-1$
.append(CUSTOM_XML_TRACE_DEFINITIONS_FILE_NAME).toString();
// TODO: These strings should not be externalized
private static final String CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT = Messages.CustomXmlTraceDefinition_definitionRootElement;
private static final String DEFINITION_ELEMENT = Messages.CustomXmlTraceDefinition_definition;
private static final String CATEGORY_ATTRIBUTE = Messages.CustomXmlTraceDefinition_category;
private static final String TAG_ATTRIBUTE = Messages.CustomXmlTraceDefinition_tag;
private static final String NAME_ATTRIBUTE = Messages.CustomXmlTraceDefinition_name;
private static final String LOG_ENTRY_ATTRIBUTE = Messages.CustomXmlTraceDefinition_logEntry;
private static final String EVENT_TYPE_ATTRIBUTE = Messages.CustomXmlTraceDefinition_eventType;
private static final String TIME_STAMP_OUTPUT_FORMAT_ELEMENT = Messages.CustomXmlTraceDefinition_timestampOutputFormat;
private static final String INPUT_ELEMENT_ELEMENT = Messages.CustomXmlTraceDefinition_inputElement;
private static final String ATTRIBUTE_ELEMENT = Messages.CustomXmlTraceDefinition_attribute;
private static final String INPUT_DATA_ELEMENT = Messages.CustomXmlTraceDefinition_inputData;
private static final String ACTION_ATTRIBUTE = Messages.CustomXmlTraceDefinition_action;
private static final String FORMAT_ATTRIBUTE = Messages.CustomXmlTraceDefinition_format;
private static final String OUTPUT_COLUMN_ELEMENT = Messages.CustomXmlTraceDefinition_outputColumn;
/**
* This is the value that the extension sets for traceContentType to be able
* to load an XML parser
**/
private static final String TRACE_CONTENT_TYPE_ATTRIBUTE_VALUE = "xml"; //$NON-NLS-1$
/** Top-level input element */
public CustomXmlInputElement rootInputElement;
/**
* Default constructor
*/
public CustomXmlTraceDefinition() {
this(CUSTOM_XML_CATEGORY, "", null, new ArrayList<OutputColumn>(), ""); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Full constructor
*
* @param category
* Category of the trace type
* @param traceType
* Name of the trace type
* @param rootElement
* The top-level XML element
* @param outputs
* The list of output columns
* @param timeStampOutputFormat
* The timestamp format to use
*/
public CustomXmlTraceDefinition(String category, String traceType, CustomXmlInputElement rootElement,
List<OutputColumn> outputs, String timeStampOutputFormat) {
this.categoryName = category;
this.definitionName = traceType;
this.rootInputElement = rootElement;
this.outputs = outputs;
this.timeStampOutputFormat = timeStampOutputFormat;
}
@Override
public void save() {
save(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
}
@Override
public void save(String path) {
try {
DocumentBuilder db = XmlUtils.newSafeDocumentBuilderFactory().newDocumentBuilder();
// The following allows xml parsing without access to the dtd
db.setEntityResolver(createEmptyEntityResolver());
// The following catches xml parsing exceptions
db.setErrorHandler(createErrorHandler());
Document doc = null;
File file = new File(path);
if (file.canRead()) {
doc = db.parse(file);
if (!doc.getDocumentElement().getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
Activator.logError(String.format("Error saving CustomXmlTraceDefinition: path=%s is not a valid custom parser file", path)); //$NON-NLS-1$
return;
}
} else {
doc = db.newDocument();
Node node = doc.createElement(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT);
doc.appendChild(node);
}
Element root = doc.getDocumentElement();
Element oldDefinitionElement = findDefinitionElement(root, categoryName, definitionName);
if (oldDefinitionElement != null) {
root.removeChild(oldDefinitionElement);
}
Element definitionElement = doc.createElement(DEFINITION_ELEMENT);
root.appendChild(definitionElement);
definitionElement.setAttribute(CATEGORY_ATTRIBUTE, categoryName);
definitionElement.setAttribute(NAME_ATTRIBUTE, definitionName);
if (timeStampOutputFormat != null && !timeStampOutputFormat.isEmpty()) {
Element formatElement = doc.createElement(TIME_STAMP_OUTPUT_FORMAT_ELEMENT);
definitionElement.appendChild(formatElement);
formatElement.appendChild(doc.createTextNode(timeStampOutputFormat));
}
if (rootInputElement != null) {
definitionElement.appendChild(createInputElementElement(rootInputElement, doc));
}
if (outputs != null) {
for (OutputColumn output : outputs) {
Element outputColumnElement = doc.createElement(OUTPUT_COLUMN_ELEMENT);
definitionElement.appendChild(outputColumnElement);
outputColumnElement.setAttribute(TAG_ATTRIBUTE, output.tag.name());
outputColumnElement.setAttribute(NAME_ATTRIBUTE, output.name);
}
}
Transformer transformer = XmlUtils.newSecureTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
// initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
try (FileWriter writer = new FileWriter(file);) {
writer.write(xmlString);
}
TmfTraceType.addCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
} catch (ParserConfigurationException | TransformerFactoryConfigurationError | TransformerException | IOException | SAXException e) {
Activator.logError("Error saving CustomXmlTraceDefinition: path=" + path, e); //$NON-NLS-1$
}
}
private Element createInputElementElement(CustomXmlInputElement inputElement, Document doc) {
Element inputElementElement = doc.createElement(INPUT_ELEMENT_ELEMENT);
inputElementElement.setAttribute(NAME_ATTRIBUTE, inputElement.getElementName());
if (inputElement.isLogEntry()) {
inputElementElement.setAttribute(LOG_ENTRY_ATTRIBUTE, Boolean.toString(inputElement.isLogEntry()));
}
if (inputElement.getEventType() != null) {
inputElementElement.setAttribute(EVENT_TYPE_ATTRIBUTE, inputElement.getEventType());
}
if (inputElement.getParentElement() != null) {
Element inputDataElement = doc.createElement(INPUT_DATA_ELEMENT);
inputElementElement.appendChild(inputDataElement);
inputDataElement.setAttribute(TAG_ATTRIBUTE, inputElement.getInputTag().name());
inputDataElement.setAttribute(NAME_ATTRIBUTE, inputElement.getInputName());
inputDataElement.setAttribute(ACTION_ATTRIBUTE, Integer.toString(inputElement.getInputAction()));
String inputFormat = inputElement.getInputFormat();
if (inputFormat != null && !inputFormat.isEmpty()) {
inputDataElement.setAttribute(FORMAT_ATTRIBUTE, inputFormat);
}
}
if (inputElement.getAttributes() != null) {
for (CustomXmlInputAttribute attribute : inputElement.getAttributes()) {
Element inputAttributeElement = doc.createElement(ATTRIBUTE_ELEMENT);
inputElementElement.appendChild(inputAttributeElement);
inputAttributeElement.setAttribute(NAME_ATTRIBUTE, attribute.getAttributeName());
Element inputDataElement = doc.createElement(INPUT_DATA_ELEMENT);
inputAttributeElement.appendChild(inputDataElement);
inputDataElement.setAttribute(TAG_ATTRIBUTE, attribute.getInputTag().name());
inputDataElement.setAttribute(NAME_ATTRIBUTE, attribute.getInputName());
inputDataElement.setAttribute(ACTION_ATTRIBUTE, Integer.toString(attribute.getInputAction()));
String inputFormat = attribute.getInputFormat();
if (inputFormat != null && !inputFormat.isEmpty()) {
inputDataElement.setAttribute(FORMAT_ATTRIBUTE, inputFormat);
}
}
}
if (inputElement.getChildElements() != null) {
for (CustomXmlInputElement childInputElement : inputElement.getChildElements()) {
inputElementElement.appendChild(createInputElementElement(childInputElement, doc));
}
}
return inputElementElement;
}
/**
* Load all custom XML trace definitions, including the user-defined and
* default (built-in) parsers.
*
* @return The loaded trace definitions
*/
public static CustomXmlTraceDefinition[] loadAll() {
return loadAll(true);
}
/**
* Load all custom XML trace definitions, including the user-defined and,
* optionally, the default (built-in) parsers.
*
* @param includeDefaults
* if true, the default (built-in) parsers are included
*
* @return The loaded trace definitions
*/
public static CustomXmlTraceDefinition[] loadAll(boolean includeDefaults) {
File defaultFile = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
File legacyFileUI = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI);
File legacyFileCore = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE);
/*
* If there is no file at the expected location, check the legacy
* locations instead.
*/
if (!defaultFile.exists()) {
if (legacyFileCore.exists()) {
transferDefinitions(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_CORE);
} else if (legacyFileUI.exists()) {
transferDefinitions(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME_LEGACY_UI);
}
}
Set<CustomXmlTraceDefinition> defs = new TreeSet<>(Comparator.comparing(CustomXmlTraceDefinition::getCategoryName).thenComparing(CustomXmlTraceDefinition::getDefinitionName));
defs.addAll(Arrays.asList(loadAll(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME)));
if (includeDefaults) {
defs.addAll(Arrays.asList(loadAll(CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME)));
// Also load definitions contributed by extensions
Collection<String> paths = getExtensionDefinitionsPaths(TRACE_CONTENT_TYPE_ATTRIBUTE_VALUE);
for (String customTraceDefinitionPath : paths) {
defs.addAll(Arrays.asList(loadAll(customTraceDefinitionPath)));
}
}
return defs.toArray(new CustomXmlTraceDefinition[0]);
}
private static void transferDefinitions(String defFile) {
CustomXmlTraceDefinition[] oldDefs = loadAll(defFile);
for (CustomXmlTraceDefinition def : oldDefs) {
/* Save in the new location */
def.save();
}
}
/**
* Load all the XML trace definitions in the given definitions file.
*
* @param path
* Path to the definitions file to load
* @return The loaded trace definitions
*/
public static CustomXmlTraceDefinition[] loadAll(String path) {
File file = new File(path);
if (!file.canRead()) {
return new CustomXmlTraceDefinition[0];
}
try (FileInputStream fis = new FileInputStream(file);) {
return loadAll(fis);
} catch (IOException e) {
Activator.logError("Error loading all in CustomXmlTraceDefinition: path=" + path, e); //$NON-NLS-1$
}
return new CustomXmlTraceDefinition[0];
}
/**
* Load all the XML trace definitions from the given stream
*
* @param stream
* An input stream from which to read the definitions
* @return The loaded trace definitions
*/
public static CustomXmlTraceDefinition[] loadAll(InputStream stream) {
try {
DocumentBuilder db = XmlUtils.newSafeDocumentBuilderFactory().newDocumentBuilder();
// The following allows xml parsing without access to the dtd
db.setEntityResolver(createEmptyEntityResolver());
// The following catches xml parsing exceptions
db.setErrorHandler(createErrorHandler());
Document doc = db.parse(stream);
Element root = doc.getDocumentElement();
if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
return new CustomXmlTraceDefinition[0];
}
ArrayList<CustomXmlTraceDefinition> defList = new ArrayList<>();
NodeList nodeList = root.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element && node.getNodeName().equals(DEFINITION_ELEMENT)) {
CustomXmlTraceDefinition def = extractDefinition((Element) node);
if (def != null) {
defList.add(def);
}
}
}
return defList.toArray(new CustomXmlTraceDefinition[0]);
} catch (ParserConfigurationException | SAXException | IOException e) {
Activator.logError("Error loading all in CustomXmlTraceDefinition: path=" + stream, e); //$NON-NLS-1$
}
return new CustomXmlTraceDefinition[0];
}
/**
* Load the given trace definition.
*
* @param categoryName
* Category of the definition to load
* @param definitionName
* Name of the XML trace definition to load
* @return The loaded trace definition
*/
public static CustomXmlTraceDefinition load(String categoryName, String definitionName) {
try {
DocumentBuilder db = XmlUtils.newSafeDocumentBuilderFactory().newDocumentBuilder();
// The following allows xml parsing without access to the dtd
EntityResolver resolver = (publicId, systemId) -> {
String empty = ""; //$NON-NLS-1$
ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
return new InputSource(bais);
};
db.setEntityResolver(resolver);
// The following catches xml parsing exceptions
db.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException saxparseexception) throws SAXException {
// Do nothing
}
@Override
public void warning(SAXParseException saxparseexception) throws SAXException {
// Do nothing
}
@Override
public void fatalError(SAXParseException saxparseexception) throws SAXException {
throw saxparseexception;
}
});
CustomXmlTraceDefinition value = lookupXmlDefinition(categoryName, definitionName, db, CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
if (value == null) {
value = lookupXmlDefinition(categoryName, definitionName, db, CUSTOM_XML_TRACE_DEFINITIONS_DEFAULT_PATH_NAME);
}
return value;
} catch (ParserConfigurationException | SAXException | IOException e) {
Activator.logError("Error loading CustomXmlTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
}
return null;
}
private static CustomXmlTraceDefinition lookupXmlDefinition(String categoryName, String definitionName, DocumentBuilder db, String source) throws SAXException, IOException {
File file = new File(source);
if (!file.exists()) {
return null;
}
Document doc = db.parse(file);
Element root = doc.getDocumentElement();
if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
return null;
}
Element definitionElement = findDefinitionElement(root, categoryName, definitionName);
if (definitionElement != null) {
return extractDefinition(definitionElement);
}
return null;
}
private static Element findDefinitionElement(Element root, String categoryName, String definitionName) {
NodeList nodeList = root.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element && node.getNodeName().equals(DEFINITION_ELEMENT)) {
Element element = (Element) node;
String categoryAttribute = element.getAttribute(CATEGORY_ATTRIBUTE);
if (categoryAttribute.isEmpty()) {
categoryAttribute = CUSTOM_XML_CATEGORY;
}
String nameAttribute = element.getAttribute(NAME_ATTRIBUTE);
if (categoryName.equals(categoryAttribute) &&
definitionName.equals(nameAttribute)) {
return element;
}
}
}
return null;
}
/**
* Extract a trace definition from an XML element.
*
* @param definitionElement
* Definition element
* @return The extracted trace definition
*/
public static CustomXmlTraceDefinition extractDefinition(Element definitionElement) {
CustomXmlTraceDefinition def = new CustomXmlTraceDefinition();
def.categoryName = definitionElement.getAttribute(CATEGORY_ATTRIBUTE);
if (def.categoryName.isEmpty()) {
def.categoryName = CUSTOM_XML_CATEGORY;
}
def.definitionName = definitionElement.getAttribute(NAME_ATTRIBUTE);
if (def.definitionName.isEmpty()) {
return null;
}
NodeList nodeList = definitionElement.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
String nodeName = node.getNodeName();
if (nodeName.equals(TIME_STAMP_OUTPUT_FORMAT_ELEMENT)) {
Element formatElement = (Element) node;
def.timeStampOutputFormat = formatElement.getTextContent();
} else if (nodeName.equals(INPUT_ELEMENT_ELEMENT)) {
CustomXmlInputElement inputElement = extractInputElement((Element) node);
if (inputElement != null) {
if (def.rootInputElement == null) {
def.rootInputElement = inputElement;
} else {
return null;
}
}
} else if (nodeName.equals(OUTPUT_COLUMN_ELEMENT)) {
Element outputColumnElement = (Element) node;
Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(outputColumnElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
OutputColumn outputColumn = new OutputColumn(entry.getKey(), entry.getValue());
def.outputs.add(outputColumn);
}
}
return def;
}
private static CustomXmlInputElement extractInputElement(Element inputElementElement) {
CustomXmlInputElement inputElement = new CustomXmlInputElement();
inputElement.setElementName(inputElementElement.getAttribute(NAME_ATTRIBUTE));
inputElement.setLogEntry((Boolean.toString(true).equals(inputElementElement.getAttribute(LOG_ENTRY_ATTRIBUTE))) ? true : false);
String eventType = inputElementElement.getAttribute(EVENT_TYPE_ATTRIBUTE);
inputElement.setEventType(eventType.isEmpty() ? null : eventType);
NodeList nodeList = inputElementElement.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
String nodeName = node.getNodeName();
if (nodeName.equals(INPUT_DATA_ELEMENT)) {
Element inputDataElement = (Element) node;
Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(inputDataElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
inputElement.setInputTag(entry.getKey());
inputElement.setInputName(entry.getValue());
inputElement.setInputAction(Integer.parseInt(inputDataElement.getAttribute(ACTION_ATTRIBUTE)));
inputElement.setInputFormat(inputDataElement.getAttribute(FORMAT_ATTRIBUTE));
} else if (nodeName.equals(ATTRIBUTE_ELEMENT)) {
Element attributeElement = (Element) node;
String attributeName = attributeElement.getAttribute(NAME_ATTRIBUTE);
NodeList attributeNodeList = attributeElement.getChildNodes();
for (int j = 0; j < attributeNodeList.getLength(); j++) {
Node attributeNode = attributeNodeList.item(j);
String attributeNodeName = attributeNode.getNodeName();
if (attributeNodeName.equals(INPUT_DATA_ELEMENT)) {
Element inputDataElement = (Element) attributeNode;
Entry<@NonNull Tag, @NonNull String> entry = extractTagAndName(inputDataElement, TAG_ATTRIBUTE, NAME_ATTRIBUTE);
int action = Integer.parseInt(inputDataElement.getAttribute(ACTION_ATTRIBUTE));
String format = inputDataElement.getAttribute(FORMAT_ATTRIBUTE);
inputElement.addAttribute(new CustomXmlInputAttribute(attributeName, entry.getKey(), entry.getValue(), action, format));
break;
}
}
} else if (nodeName.equals(INPUT_ELEMENT_ELEMENT)) {
Element childInputElementElement = (Element) node;
CustomXmlInputElement childInputElement = extractInputElement(childInputElementElement);
if (childInputElement != null) {
inputElement.addChild(childInputElement);
}
}
}
return inputElement;
}
/**
* Delete a definition from the currently loaded ones.
*
* @param categoryName
* The category of the definition to delete
* @param definitionName
* The name of the definition to delete
*/
public static void delete(String categoryName, String definitionName) {
try {
DocumentBuilder db = XmlUtils.newSafeDocumentBuilderFactory().newDocumentBuilder();
// The following allows xml parsing without access to the dtd
EntityResolver resolver = (publicId, systemId) -> {
String empty = ""; //$NON-NLS-1$
ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
return new InputSource(bais);
};
db.setEntityResolver(resolver);
// The following catches xml parsing exceptions
db.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException saxparseexception) throws SAXException {
// Do nothing
}
@Override
public void warning(SAXParseException saxparseexception) throws SAXException {
// Do nothing
}
@Override
public void fatalError(SAXParseException saxparseexception) throws SAXException {
throw saxparseexception;
}
});
File file = new File(CUSTOM_XML_TRACE_DEFINITIONS_PATH_NAME);
Document doc = db.parse(file);
Element root = doc.getDocumentElement();
if (!root.getNodeName().equals(CUSTOM_XML_TRACE_DEFINITION_ROOT_ELEMENT)) {
return;
}
Element definitionElement = findDefinitionElement(root, categoryName, definitionName);
if (definitionElement != null) {
root.removeChild(definitionElement);
}
Transformer transformer = XmlUtils.newSecureTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
// initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
try (FileWriter writer = new FileWriter(file);) {
writer.write(xmlString);
}
TmfTraceType.removeCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
// Check if default definition needs to be reloaded
TmfTraceType.addCustomTraceType(CustomXmlTrace.class, categoryName, definitionName);
} catch (ParserConfigurationException | SAXException | IOException | TransformerFactoryConfigurationError | TransformerException e) {
Activator.logError("Error deleteing CustomXmlTraceDefinition: definitionName=" + definitionName, e); //$NON-NLS-1$
}
}
}