1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal and others
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 * Jean-Christian Kouame - Add comparison between two state values
14 ******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.model
;
18 import java
.util
.ArrayList
;
19 import java
.util
.List
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
26 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.module
.IXmlStateSystemContainer
;
27 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.module
.XmlUtils
;
28 import org
.eclipse
.tracecompass
.tmf
.analysis
.xml
.core
.stateprovider
.TmfXmlStrings
;
29 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
30 import org
.w3c
.dom
.Element
;
33 * This Class implement a condition tree in the XML-defined state system.
39 * <stateAttribute type="location" value="CurrentThread" />
40 * <stateAttribute type="constant" value="System_call" />
41 * <stateValue type="null" />
44 * <stateValue type="long" value="2" />
45 * <stateValue type="long" value="5" />
50 * @author Florian Wininger
52 public class TmfXmlCondition
{
54 private final List
<TmfXmlCondition
> fConditions
= new ArrayList
<>();
55 private final List
<ITmfXmlStateValue
> fStateValues
;
56 private final LogicalOperator fOperator
;
57 private final IXmlStateSystemContainer fContainer
;
58 private final ConditionOperator fConditionOperator
;
60 private enum LogicalOperator
{
67 private enum ConditionOperator
{
81 * The factory used to create XML model elements
83 * The XML root of this condition
85 * The state system container this condition belongs to
87 public TmfXmlCondition(ITmfXmlModelFactory modelFactory
, Element node
, IXmlStateSystemContainer container
) {
88 fContainer
= container
;
90 Element rootNode
= node
;
91 /* Process the conditions: in each case, only process Element nodes */
92 List
<@Nullable Element
> childElements
= XmlUtils
.getChildElements(rootNode
);
95 * If the node is an if, take the child as the root condition
97 * FIXME: Maybe the caller should do this instead.
99 if (node
.getNodeName().equals(TmfXmlStrings
.IF
)) {
100 if (childElements
.isEmpty()) {
101 throw new IllegalArgumentException("TmfXmlCondition constructor: IF node with no child element"); //$NON-NLS-1$
103 rootNode
= NonNullUtils
.checkNotNull(childElements
.get(0));
104 childElements
= XmlUtils
.getChildElements(rootNode
);
107 switch (rootNode
.getNodeName()) {
108 case TmfXmlStrings
.CONDITION
:
109 int size
= rootNode
.getElementsByTagName(TmfXmlStrings
.STATE_VALUE
).getLength();
110 fStateValues
= new ArrayList
<>(size
);
111 fOperator
= LogicalOperator
.NONE
;
113 fConditionOperator
= getConditionOperator(rootNode
);
114 getStateValuesForXmlCondition(modelFactory
, NonNullUtils
.checkNotNull(childElements
));
116 // No need to test if the childElements size is actually 2. The
117 // XSD validation do this check already.
118 fConditionOperator
= ConditionOperator
.EQ
;
119 fStateValues
.add(modelFactory
.createStateValue(NonNullUtils
.checkNotNull(childElements
.get(0)), fContainer
, new ArrayList
<ITmfXmlStateAttribute
>()));
120 fStateValues
.add(modelFactory
.createStateValue(NonNullUtils
.checkNotNull(childElements
.get(1)), fContainer
, new ArrayList
<ITmfXmlStateAttribute
>()));
123 case TmfXmlStrings
.NOT
:
124 fStateValues
= new ArrayList
<>();
125 fOperator
= LogicalOperator
.NOT
;
126 fConditionOperator
= ConditionOperator
.NONE
;
127 Element element
= NonNullUtils
.checkNotNull(childElements
.get(0));
128 fConditions
.add(modelFactory
.createCondition(element
, fContainer
));
130 case TmfXmlStrings
.AND
:
131 fStateValues
= new ArrayList
<>();
132 fOperator
= LogicalOperator
.AND
;
133 fConditionOperator
= ConditionOperator
.NONE
;
134 for (Element condition
: childElements
) {
135 if (condition
== null) {
138 fConditions
.add(modelFactory
.createCondition(condition
, fContainer
));
141 case TmfXmlStrings
.OR
:
142 fStateValues
= new ArrayList
<>();
143 fOperator
= LogicalOperator
.OR
;
144 fConditionOperator
= ConditionOperator
.NONE
;
145 for (Element condition
: childElements
) {
146 if (condition
== null) {
149 fConditions
.add(modelFactory
.createCondition(condition
, fContainer
));
153 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
157 private void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory
, List
<@Nullable Element
> childElements
) {
158 Element stateValueElement
= NonNullUtils
.checkNotNull(childElements
.remove(childElements
.size() - 1));
160 * A state value is either preceded by an eventField or a number of
163 final Element firstElement
= NonNullUtils
.checkNotNull(childElements
.get(0));
164 if (childElements
.size() == 1 && firstElement
.getNodeName().equals(TmfXmlStrings
.ELEMENT_FIELD
)) {
165 String attribute
= firstElement
.getAttribute(TmfXmlStrings
.NAME
);
166 fStateValues
.add(modelFactory
.createStateValue(stateValueElement
, fContainer
, attribute
));
168 List
<ITmfXmlStateAttribute
> attributes
= new ArrayList
<>();
169 for (Element element
: childElements
) {
170 if (element
== null) {
171 throw new NullPointerException("There should be at list one element"); //$NON-NLS-1$
173 if (!element
.getNodeName().equals(TmfXmlStrings
.STATE_ATTRIBUTE
)) {
174 throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
176 ITmfXmlStateAttribute attribute
= modelFactory
.createStateAttribute(element
, fContainer
);
177 attributes
.add(attribute
);
179 fStateValues
.add(modelFactory
.createStateValue(stateValueElement
, fContainer
, attributes
));
183 private static ConditionOperator
getConditionOperator(Element rootNode
) {
184 String equationType
= rootNode
.getAttribute(TmfXmlStrings
.OPERATOR
);
185 switch (equationType
) {
186 case TmfXmlStrings
.EQ
:
187 return ConditionOperator
.EQ
;
188 case TmfXmlStrings
.NE
:
189 return ConditionOperator
.NE
;
190 case TmfXmlStrings
.GE
:
191 return ConditionOperator
.GE
;
192 case TmfXmlStrings
.GT
:
193 return ConditionOperator
.GT
;
194 case TmfXmlStrings
.LE
:
195 return ConditionOperator
.LE
;
196 case TmfXmlStrings
.LT
:
197 return ConditionOperator
.LT
;
198 case TmfXmlStrings
.NULL
:
199 return ConditionOperator
.EQ
;
201 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
206 * Test the result of the condition for an event
209 * The event on which to test the condition
210 * @return Whether the condition is true or not
211 * @throws AttributeNotFoundException
212 * The state attribute was not found
215 public boolean testForEvent(ITmfEvent event
) throws AttributeNotFoundException
{
216 ITmfStateSystem ss
= fContainer
.getStateSystem();
217 if (!fStateValues
.isEmpty()) {
218 return testForEvent(event
, NonNullUtils
.checkNotNull(ss
));
219 } else if (!fConditions
.isEmpty()) {
220 /* Verify a condition tree */
223 for (TmfXmlCondition childCondition
: fConditions
) {
224 if (!childCondition
.testForEvent(event
)) {
232 return !fConditions
.get(0).testForEvent(event
);
234 for (TmfXmlCondition childCondition
: fConditions
) {
235 if (childCondition
.testForEvent(event
)) {
248 private boolean testForEvent(ITmfEvent event
, ITmfStateSystem ss
) throws AttributeNotFoundException
{
250 * The condition is either the equality check of a state value or a
251 * boolean operation on other conditions
253 if (fStateValues
.size() == 1) {
254 ITmfXmlStateValue filter
= fStateValues
.get(0);
255 int quark
= IXmlStateSystemContainer
.ROOT_QUARK
;
256 for (ITmfXmlStateAttribute attribute
: filter
.getAttributes()) {
257 quark
= attribute
.getAttributeQuark(event
, quark
);
259 * When verifying a condition, the state attribute must exist,
260 * if it does not, the query is not valid, we stop the condition
263 if (quark
== IXmlStateSystemContainer
.ERROR_QUARK
) {
264 throw new AttributeNotFoundException(ss
.getSSID() + " Attribute:" + attribute
); //$NON-NLS-1$
269 * The actual value: it can be either queried in the state system or
272 ITmfStateValue valueState
= (quark
!= IXmlStateSystemContainer
.ROOT_QUARK
) ? ss
.queryOngoingState(quark
) : filter
.getEventFieldValue(event
);
273 if (valueState
== null) {
274 throw new IllegalStateException("TmfXmlCondition : The state value does not exist in the state system"); //$NON-NLS-1$
277 /* Get the value to compare to from the XML file */
278 ITmfStateValue valueXML
;
279 valueXML
= filter
.getValue(event
);
280 return compare(valueState
, valueXML
, fConditionOperator
);
282 /* Get the two values needed for the comparison */
283 ITmfStateValue valuesXML1
= fStateValues
.get(0).getValue(event
);
284 ITmfStateValue valuesXML2
= fStateValues
.get(1).getValue(event
);
285 return valuesXML1
.equals(valuesXML2
);
289 public String
toString() {
290 StringBuilder output
= new StringBuilder("TmfXmlCondition: "); //$NON-NLS-1$
291 if (fOperator
!= LogicalOperator
.NONE
) {
292 output
.append(fOperator
).append(" on ").append(fConditions
); //$NON-NLS-1$
294 output
.append(fConditionOperator
).append(" {").append(fStateValues
.get(0)); //$NON-NLS-1$
295 if (fStateValues
.size() == 2) {
296 output
.append(", ").append(fStateValues
.get(1)); //$NON-NLS-1$
298 output
.append("}"); //$NON-NLS-1$
300 return output
.toString();
304 * Compare two ITmfStateValues based on the given comparison operator
307 * the state value to compare to
309 * the state value to be compared with
310 * @param comparisonOperator
311 * the operator to compare the inputs
312 * @return the boolean result of the comparison
314 public boolean compare(ITmfStateValue source
, ITmfStateValue dest
, ConditionOperator comparisonOperator
) {
315 switch (comparisonOperator
) {
316 //TODO The comparison operator should have a compareHelper that calls compare
318 return (source
.compareTo(dest
) == 0);
320 return (source
.compareTo(dest
) != 0);
322 return (source
.compareTo(dest
) >= 0);
324 return (source
.compareTo(dest
) > 0);
326 return (source
.compareTo(dest
) <= 0);
328 return (source
.compareTo(dest
) < 0);
331 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$