1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal
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
10 * Florian Wininger - Initial API and implementation
11 * Naser Ezzati - Add the comparison operators
12 * Patrick Tasse - Add message to exceptions
13 ******************************************************************************/
15 package org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.model
;
17 import java
.util
.ArrayList
;
18 import java
.util
.List
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
24 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.module
.IXmlStateSystemContainer
;
25 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.module
.XmlUtils
;
26 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.stateprovider
.TmfXmlStrings
;
27 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
28 import org
.w3c
.dom
.Element
;
31 * This Class implement a condition tree in the XML-defined state system.
37 * <stateAttribute type="location" value="CurrentThread" />
38 * <stateAttribute type="constant" value="System_call" />
39 * <stateValue type="null" />
46 * @author Florian Wininger
48 public class TmfXmlCondition
{
50 private final List
<TmfXmlCondition
> fConditions
= new ArrayList
<>();
51 private final @Nullable ITmfXmlStateValue fStateValue
;
52 private final LogicalOperator fOperator
;
53 private final IXmlStateSystemContainer fContainer
;
54 private final ConditionOperator fConditionOperator
;
56 private enum LogicalOperator
{
63 private enum ConditionOperator
{
77 * The factory used to create XML model elements
79 * The XML root of this condition
81 * The state system container this condition belongs to
83 public TmfXmlCondition(ITmfXmlModelFactory modelFactory
, Element node
, IXmlStateSystemContainer container
) {
84 fContainer
= container
;
86 Element rootNode
= node
;
87 /* Process the conditions: in each case, only process Element nodes */
88 List
<@Nullable Element
> childElements
= XmlUtils
.getChildElements(rootNode
);
91 * If the node is an if, take the child as the root condition
93 * FIXME: Maybe the caller should do this instead.
95 if (node
.getNodeName().equals(TmfXmlStrings
.IF
)) {
96 if (childElements
.isEmpty()) {
97 throw new IllegalArgumentException("TmfXmlCondition constructor: IF node has no child element"); //$NON-NLS-1$
99 rootNode
= childElements
.get(0);
100 childElements
= XmlUtils
.getChildElements(rootNode
);
103 if (rootNode
== null) {
104 throw new IllegalArgumentException();
107 switch (rootNode
.getNodeName()) {
108 case TmfXmlStrings
.CONDITION
:
109 fOperator
= LogicalOperator
.NONE
;
110 /* Read comparison type */
111 String equationType
= rootNode
.getAttribute(TmfXmlStrings
.OPERATOR
);
113 switch (equationType
) {
114 case TmfXmlStrings
.EQ
:
115 fConditionOperator
= ConditionOperator
.EQ
;
117 case TmfXmlStrings
.NE
:
118 fConditionOperator
= ConditionOperator
.NE
;
120 case TmfXmlStrings
.GE
:
121 fConditionOperator
= ConditionOperator
.GE
;
123 case TmfXmlStrings
.GT
:
124 fConditionOperator
= ConditionOperator
.GT
;
126 case TmfXmlStrings
.LE
:
127 fConditionOperator
= ConditionOperator
.LE
;
129 case TmfXmlStrings
.LT
:
130 fConditionOperator
= ConditionOperator
.LT
;
132 case TmfXmlStrings
.NULL
:
133 fConditionOperator
= ConditionOperator
.EQ
;
136 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
138 /* The last element is a state value node */
139 Element stateValueElement
= childElements
.remove(childElements
.size() - 1);
140 if (stateValueElement
== null) {
141 throw new IllegalStateException();
145 * A state value is either preceded by an eventField or a number of
148 @Nullable Element firstChild
= childElements
.get(0);
149 if (firstChild
== null) {
150 throw new IllegalStateException();
153 if (childElements
.size() == 1 && firstChild
.getNodeName().equals(TmfXmlStrings
.ELEMENT_FIELD
)) {
154 String attribute
= firstChild
.getAttribute(TmfXmlStrings
.NAME
);
155 if (attribute
== null) {
156 throw new IllegalArgumentException();
158 fStateValue
= modelFactory
.createStateValue(stateValueElement
, fContainer
, attribute
);
160 List
<ITmfXmlStateAttribute
> attributes
= new ArrayList
<>();
161 for (Element element
: childElements
) {
162 if (element
== null || !element
.getNodeName().equals(TmfXmlStrings
.STATE_ATTRIBUTE
)) {
163 throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
165 ITmfXmlStateAttribute attribute
= modelFactory
.createStateAttribute(element
, fContainer
);
166 attributes
.add(attribute
);
168 fStateValue
= modelFactory
.createStateValue(stateValueElement
, fContainer
, attributes
);
171 case TmfXmlStrings
.NOT
:
172 fOperator
= LogicalOperator
.NOT
;
174 fConditionOperator
= ConditionOperator
.NONE
;
175 Element element
= childElements
.get(0);
176 if (element
== null) {
177 throw new IllegalArgumentException();
179 fConditions
.add(modelFactory
.createCondition(element
, fContainer
));
181 case TmfXmlStrings
.AND
:
182 fOperator
= LogicalOperator
.AND
;
184 fConditionOperator
= ConditionOperator
.NONE
;
185 for (Element condition
: childElements
) {
186 if (condition
== null) {
189 fConditions
.add(modelFactory
.createCondition(condition
, fContainer
));
192 case TmfXmlStrings
.OR
:
193 fOperator
= LogicalOperator
.OR
;
195 fConditionOperator
= ConditionOperator
.NONE
;
196 for (Element condition
: childElements
) {
197 if (condition
== null) {
200 fConditions
.add(modelFactory
.createCondition(condition
, fContainer
));
204 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
209 * Test the result of the condition for an event
212 * The event on which to test the condition
213 * @return Whether the condition is true or not
214 * @throws AttributeNotFoundException
215 * The state attribute was not found
217 public boolean testForEvent(ITmfEvent event
) throws AttributeNotFoundException
{
218 ITmfStateSystem ss
= fContainer
.getStateSystem();
220 * The condition is either the equality check of a state value or a
221 * boolean operation on other conditions
223 if (fStateValue
!= null) {
224 ITmfXmlStateValue filter
= fStateValue
;
225 int quark
= IXmlStateSystemContainer
.ROOT_QUARK
;
226 for (ITmfXmlStateAttribute attribute
: filter
.getAttributes()) {
227 quark
= attribute
.getAttributeQuark(event
, quark
);
229 * When verifying a condition, the state attribute must exist,
230 * if it does not, the query is not valid, we stop the condition
233 if (quark
== IXmlStateSystemContainer
.ERROR_QUARK
) {
234 throw new AttributeNotFoundException(ss
.getSSID() + " Attribute:" + attribute
); //$NON-NLS-1$
238 /* Get the value to compare to from the XML file */
239 ITmfStateValue valueXML
;
240 valueXML
= filter
.getValue(event
);
243 * The actual value: it can be either queried in the state system or
246 ITmfStateValue valueState
= (quark
!= IXmlStateSystemContainer
.ROOT_QUARK
) ? ss
.queryOngoingState(quark
) :
247 filter
.getEventFieldValue(event
);
248 if (valueState
== null) {
249 throw new IllegalStateException();
252 return compare(valueState
, valueXML
, fConditionOperator
);
254 } else if (!fConditions
.isEmpty()) {
255 /* Verify a condition tree */
258 for (TmfXmlCondition childCondition
: fConditions
) {
259 if (!childCondition
.testForEvent(event
)) {
267 return !fConditions
.get(0).testForEvent(event
);
269 for (TmfXmlCondition childCondition
: fConditions
) {
270 if (childCondition
.testForEvent(event
)) {
280 throw new IllegalStateException("TmfXmlCondition: the condition should be either a state value or be the result of a condition tree"); //$NON-NLS-1$
286 public String
toString() {
287 return "TmfXmlCondition: " + fOperator
+ " on " + fConditions
; //$NON-NLS-1$ //$NON-NLS-2$
291 * Compare two ITmfStateValues based on the given comparison operator
294 * the state value to compare to
296 * the state value to be compared with
297 * @param comparisonOperator
298 * the operator to compare the inputs
299 * @return the boolean result of the comparison
301 public boolean compare(ITmfStateValue source
, ITmfStateValue dest
, ConditionOperator comparisonOperator
) {
302 switch (comparisonOperator
) {
304 return (source
.compareTo(dest
) == 0);
306 return (source
.compareTo(dest
) != 0);
308 return (source
.compareTo(dest
) >= 0);
310 return (source
.compareTo(dest
) > 0);
312 return (source
.compareTo(dest
) <= 0);
314 return (source
.compareTo(dest
) < 0);
317 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$