blob: bec91266998aa9fc91294133fb87c947d10d767b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* 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
*******************************************************************************/
package org.eclipse.tracecompass.tmf.analysis.xml.core.module;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Class containing some utilities methods that can be used by analyses
* extending the XML schema
*
* @author Geneviève Bastien
* @since 2.2
*/
public final class TmfXmlUtils {
private TmfXmlUtils() {
}
/**
* Get the XML children element of an XML element, but only those of a
* certain type
*
* @param parent
* The parent element to get the children from
* @param elementTag
* The tag of the elements to return
* @return The list of children {@link Element} of the parent
*/
public static @NonNull List<@NonNull Element> getChildElements(Element parent, String elementTag) {
/* get the state providers and find the corresponding one */
NodeList nodes = parent.getElementsByTagName(elementTag);
List<@NonNull Element> childElements = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
Element node = (Element) nodes.item(i);
if (node.getParentNode().equals(parent)) {
childElements.add(node);
}
}
return childElements;
}
/**
* Return the node element corresponding to the requested type in the file.
*
* TODO: Nothing prevents from having duplicate type -> id in a same file.
* That should not be allowed. If you want an element with the same ID as
* another one, it should be in a different file and we should check it at
* validation time.
*
* @param filePath
* The absolute path to the XML file
* @param elementType
* The type of top level element to search for
* @param elementId
* The ID of the desired element
* @return The XML element or <code>null</code> if not found
*/
public static Element getElementInFile(String filePath, @NonNull String elementType, @NonNull String elementId) {
if (filePath == null) {
return null;
}
IPath path = new Path(filePath);
File file = path.toFile();
if (file == null || !file.exists() || !file.isFile() || !XmlUtils.xmlValidate(file).isOK()) {
return null;
}
try {
Document doc = XmlUtils.getDocumentFromFile(file);
/* get the state providers and find the corresponding one */
NodeList nodes = doc.getElementsByTagName(elementType);
Element foundNode = null;
for (int i = 0; i < nodes.getLength(); i++) {
Element node = (Element) nodes.item(i);
String id = node.getAttribute(TmfXmlStrings.ID);
if (id.equals(elementId)) {
foundNode = node;
}
}
return foundNode;
} catch (ParserConfigurationException | SAXException | IOException e) {
return null;
}
}
/**
* Return the ITmfStateValue.Type corresponding to the given type name.
*
* @param typeName
* The ITmfStateValue.Type name.
*
* @return The ITmfStateValue.Type
* @since 2.3
*/
public static ITmfStateValue.@Nullable Type getTmfStateValueByName(@NonNull String typeName){
ITmfStateValue.Type type;
switch (typeName) {
case TmfXmlStrings.TYPE_STRING:
type = ITmfStateValue.Type.STRING;
break;
case TmfXmlStrings.TYPE_INT:
type = ITmfStateValue.Type.INTEGER;
break;
case TmfXmlStrings.TYPE_LONG:
type = ITmfStateValue.Type.LONG;
break;
case TmfXmlStrings.TYPE_DOUBLE:
type = ITmfStateValue.Type.DOUBLE;
break;
case TmfXmlStrings.TYPE_CUSTOM:
type = ITmfStateValue.Type.CUSTOM;
break;
case TmfXmlStrings.TYPE_NULL:
type = ITmfStateValue.Type.NULL;
break;
default:
return null;
}
return type;
}
/**
* Factory constructor for Object state values
*
* @param objValue
* The object value to contain
* @return The newly-created TmfStateValue object
* @since 2.3
*/
public static @NonNull TmfStateValue newTmfStateValueFromObject(@Nullable Object objValue) {
TmfStateValue value = TmfStateValue.nullValue();
if (objValue instanceof String) {
value = TmfStateValue.newValueString((String) objValue);
} else if (objValue instanceof Long) {
value = TmfStateValue.newValueLong((Long) objValue);
} else if (objValue instanceof Integer) {
value = TmfStateValue.newValueInt((Integer) objValue);
} else if (objValue instanceof Double) {
value = TmfStateValue.newValueDouble((Double) objValue);
}
return value;
}
/**
* Factory constructor for Object state values with a forced type.
*
* @param objValue
* The object value to contain
* @param forcedType
* The forced type
* @return The newly-created TmfStateValue object
* @since 2.3
*/
public static @NonNull TmfStateValue newTmfStateValueFromObjectWithForcedType(@Nullable Object objValue, ITmfStateValue.@NonNull Type forcedType) {
if (objValue == null) {
return TmfStateValue.nullValue();
}
TmfStateValue value = TmfStateValue.nullValue();
if (objValue instanceof String) {
String fieldString = (String) objValue;
switch (forcedType) {
case INTEGER:
value = TmfStateValue.newValueInt(Integer.parseInt(fieldString));
break;
case LONG:
value = TmfStateValue.newValueLong(Long.parseLong(fieldString));
break;
case DOUBLE:
value = TmfStateValue.newValueDouble(Double.parseDouble(fieldString));
break;
case CUSTOM:
throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
case STRING:
case NULL:
default:
value = TmfStateValue.newValueString(fieldString);
break;
}
} else if (objValue instanceof Long) {
Long fieldLong = (Long) objValue;
switch (forcedType) {
case INTEGER:
value = TmfStateValue.newValueInt(fieldLong.intValue());
break;
case STRING:
value = TmfStateValue.newValueString(fieldLong.toString());
break;
case DOUBLE:
value = TmfStateValue.newValueDouble(fieldLong.doubleValue());
break;
case CUSTOM:
throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
case LONG:
case NULL:
default:
value = TmfStateValue.newValueLong(fieldLong);
break;
}
} else if (objValue instanceof Integer) {
Integer fieldInteger = (Integer) objValue;
switch (forcedType) {
case LONG:
value = TmfStateValue.newValueLong(fieldInteger.longValue());
break;
case STRING:
value = TmfStateValue.newValueString(fieldInteger.toString());
break;
case DOUBLE:
value = TmfStateValue.newValueDouble(fieldInteger.doubleValue());
break;
case CUSTOM:
throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
case INTEGER:
case NULL:
default:
value = TmfStateValue.newValueInt(fieldInteger);
break;
}
} else if (objValue instanceof Double) {
Double fieldDouble = (Double) objValue;
switch (forcedType) {
case LONG:
value = TmfStateValue.newValueLong(fieldDouble.longValue());
break;
case STRING:
value = TmfStateValue.newValueString(fieldDouble.toString());
break;
case INTEGER:
value = TmfStateValue.newValueInt(fieldDouble.intValue());
break;
case CUSTOM:
throw new IllegalStateException("Custom type cannot be forced"); //$NON-NLS-1$
case DOUBLE:
case NULL:
default:
value = TmfStateValue.newValueDouble(fieldDouble);
break;
}
} else {
value = TmfStateValue.newValueString(objValue.toString());
}
return value;
}
/**
* Get the list of analysis IDs this view is for, as listed in the header of
* the XML element
*
* @param viewElement
* The XML view element from which to get the analysis IDs
* @return The list of all analysis IDs this view is for
* @since 2.4
*/
public static @NonNull Set<@NonNull String> getViewAnalysisIds(Element viewElement) {
List<Element> heads = getChildElements(viewElement, TmfXmlStrings.HEAD);
Set<@NonNull String> analysisIds = new HashSet<>();
if (!heads.isEmpty()) {
Element head = heads.get(0);
/* Get the application analysis from the view's XML header */
List<Element> applicableAnalysis = getChildElements(head, TmfXmlStrings.ANALYSIS);
for (Element oneAnalysis : applicableAnalysis) {
analysisIds.add(oneAnalysis.getAttribute(TmfXmlStrings.ID));
}
}
return analysisIds;
}
}