/*******************************************************************************
- * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal
+ * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal and others
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* Florian Wininger - Initial API and implementation
* Naser Ezzati - Add the comparison operators
* Patrick Tasse - Add message to exceptions
+ * Jean-Christian Kouame - Add comparison between two state values
******************************************************************************/
package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
* <stateValue type="null" />
* </condition>
* <condition>
+ * <stateValue type="long" value="2" />
+ * <stateValue type="long" value="5" />
* </condition>
* </and>
* </pre>
*
* @author Florian Wininger
*/
-public class TmfXmlCondition {
+public class TmfXmlCondition implements ITmfXmlCondition {
private final List<TmfXmlCondition> fConditions = new ArrayList<>();
- private final @Nullable ITmfXmlStateValue fStateValue;
+ private final List<ITmfXmlStateValue> fStateValues;
private final LogicalOperator fOperator;
private final IXmlStateSystemContainer fContainer;
private final ConditionOperator fConditionOperator;
+ private ConditionType fType;
+ private @Nullable TmfXmlTimestampCondition fTimeCondition;
private enum LogicalOperator {
NONE,
NOT,
AND,
- OR,
+ OR
}
private enum ConditionOperator {
LT
}
+ // TODO The XmlCondition needs to be split into several classes of condition
+ // instead of using an enum
+ private enum ConditionType {
+ DATA,
+ TIME,
+ NONE
+ }
+
/**
- * Constructor
+ * Factory to create {@link TmfXmlCondition}
*
* @param modelFactory
* The factory used to create XML model elements
* The XML root of this condition
* @param container
* The state system container this condition belongs to
+ * @return The new {@link TmfXmlCondition}
+ * @since 2.0
*/
- public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
- fContainer = container;
-
+ public static TmfXmlCondition create(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
Element rootNode = node;
/* Process the conditions: in each case, only process Element nodes */
- List<Element> childElements = XmlUtils.getChildElements(rootNode);
+ List<@Nullable Element> childElements = XmlUtils.getChildElements(rootNode);
/*
* If the node is an if, take the child as the root condition
*/
if (node.getNodeName().equals(TmfXmlStrings.IF)) {
if (childElements.isEmpty()) {
- throw new IllegalArgumentException("TmfXmlCondition constructor: IF node has no child element"); //$NON-NLS-1$
+ throw new IllegalArgumentException("TmfXmlCondition constructor: IF node with no child element"); //$NON-NLS-1$
}
- rootNode = childElements.get(0);
+ rootNode = NonNullUtils.checkNotNull(childElements.get(0));
childElements = XmlUtils.getChildElements(rootNode);
}
+ List<@NonNull TmfXmlCondition> conditions = new ArrayList<>();
switch (rootNode.getNodeName()) {
case TmfXmlStrings.CONDITION:
- fOperator = LogicalOperator.NONE;
- /* Read comparison type */
- String equationType = rootNode.getAttribute(TmfXmlStrings.OPERATOR);
-
- switch (equationType) {
- case TmfXmlStrings.EQ:
- fConditionOperator = ConditionOperator.EQ;
- break;
- case TmfXmlStrings.NE:
- fConditionOperator = ConditionOperator.NE;
- break;
- case TmfXmlStrings.GE:
- fConditionOperator = ConditionOperator.GE;
- break;
- case TmfXmlStrings.GT:
- fConditionOperator = ConditionOperator.GT;
- break;
- case TmfXmlStrings.LE:
- fConditionOperator = ConditionOperator.LE;
- break;
- case TmfXmlStrings.LT:
- fConditionOperator = ConditionOperator.LT;
- break;
- case TmfXmlStrings.NULL:
- fConditionOperator = ConditionOperator.EQ;
- break;
- default:
- throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
- }
- /* The last element is a state value node */
- Element stateValueElement = childElements.remove(childElements.size() - 1);
- if (stateValueElement == null) {
- throw new IllegalStateException();
- }
+ return createPatternCondition(modelFactory, container, rootNode, childElements);
+ case TmfXmlStrings.NOT:
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.NOT, conditions);
+ case TmfXmlStrings.AND:
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.AND, conditions);
+ case TmfXmlStrings.OR:
+ return createMultipleCondition(modelFactory, container, childElements, LogicalOperator.OR, conditions);
+ default:
+ throw new IllegalArgumentException("TmfXmlCondition constructor: XML node " + rootNode.getNodeName() + " is of the wrong type"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
- /*
- * A state value is either preceded by an eventField or a number of
- * state attributes
- */
- if (childElements.size() == 1 && childElements.get(0).getNodeName().equals(TmfXmlStrings.ELEMENT_FIELD)) {
- String attribute = childElements.get(0).getAttribute(TmfXmlStrings.NAME);
- if (attribute == null) {
- throw new IllegalArgumentException();
- }
- fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, attribute);
+ private static TmfXmlCondition createPatternCondition(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, Element rootNode, List<@Nullable Element> childElements) {
+ ArrayList<ITmfXmlStateValue> stateValues;
+ ConditionOperator conditionOperator;
+ TmfXmlTimestampCondition timeCondition = null;
+ int size = rootNode.getElementsByTagName(TmfXmlStrings.STATE_VALUE).getLength();
+ if (size != 0) {
+ stateValues = new ArrayList<>(size);
+ if (size == 1) {
+ conditionOperator = getConditionOperator(rootNode);
+ getStateValuesForXmlCondition(modelFactory, NonNullUtils.checkNotNull(childElements), stateValues, container);
} else {
- List<ITmfXmlStateAttribute> attributes = new ArrayList<>();
- for (Element element : childElements) {
- if (!element.getNodeName().equals(TmfXmlStrings.STATE_ATTRIBUTE)) {
- throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
- }
- ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
- attributes.add(attribute);
- }
- fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, attributes);
+ // No need to test if the childElements size is actually 2.
+ // The XSD validation do this check already.
+ conditionOperator = ConditionOperator.EQ;
+ stateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(0)), container, new ArrayList<ITmfXmlStateAttribute>()));
+ stateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), container, new ArrayList<ITmfXmlStateAttribute>()));
}
- break;
- case TmfXmlStrings.NOT:
- fOperator = LogicalOperator.NOT;
- fStateValue = null;
- fConditionOperator = ConditionOperator.NONE;
- Element element = childElements.get(0);
- if (element == null) {
- throw new IllegalArgumentException();
+ return new TmfXmlCondition(ConditionType.DATA, stateValues, LogicalOperator.NONE, conditionOperator, null, new ArrayList<>(), container);
+ }
+ final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
+ timeCondition = modelFactory.createTimestampsCondition(firstElement, container);
+ return new TmfXmlCondition(ConditionType.TIME, new ArrayList<>(), LogicalOperator.NONE, ConditionOperator.EQ, timeCondition, new ArrayList<>(), container);
+ }
+
+ private static TmfXmlCondition createMultipleCondition(ITmfXmlModelFactory modelFactory, IXmlStateSystemContainer container, List<@Nullable Element> childElements, LogicalOperator op,
+ List<@NonNull TmfXmlCondition> conditions) {
+ for (Element condition : childElements) {
+ if (condition == null) {
+ continue;
}
- fConditions.add(modelFactory.createCondition(element, fContainer));
- break;
- case TmfXmlStrings.AND:
- fOperator = LogicalOperator.AND;
- fStateValue = null;
- fConditionOperator = ConditionOperator.NONE;
- for (Element condition : childElements) {
- if (condition == null) {
- continue;
+ conditions.add(modelFactory.createCondition(condition, container));
+ }
+ return new TmfXmlCondition(ConditionType.NONE, new ArrayList<>(), op, ConditionOperator.NONE, null, conditions, container);
+ }
+
+ private TmfXmlCondition(ConditionType type, ArrayList<@NonNull ITmfXmlStateValue> stateValues, LogicalOperator operator, ConditionOperator conditionOperator, @Nullable TmfXmlTimestampCondition timeCondition, List<@NonNull TmfXmlCondition> conditions,
+ IXmlStateSystemContainer container) {
+ fType = type;
+ fStateValues = stateValues;
+ fOperator = operator;
+ fTimeCondition = timeCondition;
+ fContainer = container;
+ fConditions.addAll(conditions);
+ fConditionOperator = conditionOperator;
+ }
+
+ private static void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory, List<@Nullable Element> childElements, List<ITmfXmlStateValue> stateValues, IXmlStateSystemContainer container) {
+ Element stateValueElement = NonNullUtils.checkNotNull(childElements.remove(childElements.size() - 1));
+ /*
+ * A state value is either preceded by an eventField or a number of
+ * state attributes
+ */
+ final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
+ if (childElements.size() == 1 && firstElement.getNodeName().equals(TmfXmlStrings.ELEMENT_FIELD)) {
+ String attribute = firstElement.getAttribute(TmfXmlStrings.NAME);
+ stateValues.add(modelFactory.createStateValue(stateValueElement, container, attribute));
+ } else {
+ List<ITmfXmlStateAttribute> attributes = new ArrayList<>();
+ for (Element element : childElements) {
+ if (element == null) {
+ throw new NullPointerException("There should be at list one element"); //$NON-NLS-1$
}
- fConditions.add(modelFactory.createCondition(condition, fContainer));
- }
- break;
- case TmfXmlStrings.OR:
- fOperator = LogicalOperator.OR;
- fStateValue = null;
- fConditionOperator = ConditionOperator.NONE;
- for (Element condition : childElements) {
- if (condition == null) {
- continue;
+ if (!element.getNodeName().equals(TmfXmlStrings.STATE_ATTRIBUTE)) {
+ throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
}
- fConditions.add(modelFactory.createCondition(condition, fContainer));
+ ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, container);
+ attributes.add(attribute);
}
- break;
+ stateValues.add(modelFactory.createStateValue(stateValueElement, container, attributes));
+ }
+ }
+
+ private static ConditionOperator getConditionOperator(Element rootNode) {
+ String equationType = rootNode.getAttribute(TmfXmlStrings.OPERATOR);
+ switch (equationType) {
+ case TmfXmlStrings.EQ:
+ return ConditionOperator.EQ;
+ case TmfXmlStrings.NE:
+ return ConditionOperator.NE;
+ case TmfXmlStrings.GE:
+ return ConditionOperator.GE;
+ case TmfXmlStrings.GT:
+ return ConditionOperator.GT;
+ case TmfXmlStrings.LE:
+ return ConditionOperator.LE;
+ case TmfXmlStrings.LT:
+ return ConditionOperator.LT;
+ case TmfXmlStrings.NULL:
+ return ConditionOperator.EQ;
default:
- throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
+ throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
}
}
/**
- * Test the result of the condition for an event
- *
- * @param event
- * The event on which to test the condition
- * @return Whether the condition is true or not
- * @throws AttributeNotFoundException
- * The state attribute was not found
+ * @since 2.0
*/
- public boolean testForEvent(ITmfEvent event) throws AttributeNotFoundException {
+ @Override
+ public boolean test(ITmfEvent event, @Nullable TmfXmlScenarioInfo scenarioInfo) {
ITmfStateSystem ss = fContainer.getStateSystem();
- /*
- * The condition is either the equality check of a state value or a
- * boolean operation on other conditions
- */
- if (fStateValue != null) {
- ITmfXmlStateValue filter = fStateValue;
- int quark = IXmlStateSystemContainer.ROOT_QUARK;
- for (ITmfXmlStateAttribute attribute : filter.getAttributes()) {
- quark = attribute.getAttributeQuark(event, quark);
- /*
- * When verifying a condition, the state attribute must exist,
- * if it does not, the query is not valid, we stop the condition
- * check
- */
- if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
- throw new AttributeNotFoundException(ss.getSSID() + " Attribute:" + attribute); //$NON-NLS-1$
- }
+ if (fType == ConditionType.DATA) {
+ try {
+ return testForEvent(event, NonNullUtils.checkNotNull(ss), scenarioInfo);
+ } catch (AttributeNotFoundException e) {
+ Activator.logError("Attribute not found", e); //$NON-NLS-1$
+ return false;
}
-
- /* Get the value to compare to from the XML file */
- ITmfStateValue valueXML;
- valueXML = filter.getValue(event);
-
- /*
- * The actual value: it can be either queried in the state system or
- * found in the event
- */
- ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) :
- filter.getEventFieldValue(event);
- if (valueState == null) {
- throw new IllegalStateException();
+ } else if (fType == ConditionType.TIME) {
+ if (fTimeCondition != null) {
+ return fTimeCondition.test(event, scenarioInfo);
}
-
- return compare(valueState, valueXML, fConditionOperator);
-
} else if (!fConditions.isEmpty()) {
/* Verify a condition tree */
switch (fOperator) {
case AND:
- for (TmfXmlCondition childCondition : fConditions) {
- if (!childCondition.testForEvent(event)) {
+ for (ITmfXmlCondition childCondition : fConditions) {
+ if (!childCondition.test(event, scenarioInfo)) {
return false;
}
}
case NONE:
break;
case NOT:
- return !fConditions.get(0).testForEvent(event);
+ return !fConditions.get(0).test(event, scenarioInfo);
case OR:
- for (TmfXmlCondition childCondition : fConditions) {
- if (childCondition.testForEvent(event)) {
+ for (ITmfXmlCondition childCondition : fConditions) {
+ if (childCondition.test(event, scenarioInfo)) {
return true;
}
}
break;
}
- } else {
- throw new IllegalStateException("TmfXmlCondition: the condition should be either a state value or be the result of a condition tree"); //$NON-NLS-1$
}
return true;
}
+ private boolean testForEvent(ITmfEvent event, ITmfStateSystem ss, @Nullable TmfXmlScenarioInfo scenarioInfo) throws AttributeNotFoundException {
+ /*
+ * The condition is either the equality check of a state value or a
+ * boolean operation on other conditions
+ */
+ if (fStateValues.size() == 1) {
+ ITmfXmlStateValue filter = fStateValues.get(0);
+ int quark = IXmlStateSystemContainer.ROOT_QUARK;
+ for (ITmfXmlStateAttribute attribute : filter.getAttributes()) {
+ quark = attribute.getAttributeQuark(event, quark, scenarioInfo);
+ /*
+ * When verifying a condition, the state attribute must exist,
+ * if it does not, the query is not valid, we stop the condition
+ * check
+ */
+ if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
+ throw new AttributeNotFoundException(ss.getSSID() + " Attribute:" + attribute); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * The actual value: it can be either queried in the state system or
+ * found in the event
+ */
+ ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) : filter.getEventFieldValue(event);
+
+ /* Get the value to compare to from the XML file */
+ ITmfStateValue valueXML;
+ valueXML = filter.getValue(event, scenarioInfo);
+ return compare(valueState, valueXML, fConditionOperator);
+ }
+ /* Get the two values needed for the comparison */
+ ITmfStateValue valuesXML1 = fStateValues.get(0).getValue(event, scenarioInfo);
+ ITmfStateValue valuesXML2 = fStateValues.get(1).getValue(event, scenarioInfo);
+ return valuesXML1.equals(valuesXML2);
+ }
+
@Override
public String toString() {
- return "TmfXmlCondition: " + fOperator + " on " + fConditions; //$NON-NLS-1$ //$NON-NLS-2$
+ StringBuilder output = new StringBuilder("TmfXmlCondition: "); //$NON-NLS-1$
+ if (fOperator != LogicalOperator.NONE) {
+ output.append(fOperator).append(" on ").append(fConditions); //$NON-NLS-1$
+ } else {
+ output.append(fConditionOperator).append(" {").append(fStateValues.get(0)); //$NON-NLS-1$
+ if (fStateValues.size() == 2) {
+ output.append(", ").append(fStateValues.get(1)); //$NON-NLS-1$
+ }
+ output.append("}"); //$NON-NLS-1$
+ }
+ return output.toString();
}
/**
*/
public boolean compare(ITmfStateValue source, ITmfStateValue dest, ConditionOperator comparisonOperator) {
switch (comparisonOperator) {
+ // TODO The comparison operator should have a compareHelper that calls compare
case EQ:
return (source.compareTo(dest) == 0);
case NE:
default:
throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
}
-
}
-
}
\ No newline at end of file