ebb4e6598e20a8558adfc7a66611c5e4b3b32e2a
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.core / src / org / eclipse / tracecompass / tmf / analysis / xml / core / model / TmfXmlCondition.java
1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal
3 *
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
8 *
9 * Contributors:
10 * Florian Wininger - Initial API and implementation
11 * Naser Ezzati - Add the comparison operators
12 * Patrick Tasse - Add message to exceptions
13 ******************************************************************************/
14
15 package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
16
17 import java.util.ArrayList;
18 import java.util.List;
19
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;
29
30 /**
31 * This Class implement a condition tree in the XML-defined state system.
32 *
33 * <pre>
34 * example:
35 * <and>
36 * <condition>
37 * <stateAttribute type="location" value="CurrentThread" />
38 * <stateAttribute type="constant" value="System_call" />
39 * <stateValue type="null" />
40 * </condition>
41 * <condition>
42 * </condition>
43 * </and>
44 * </pre>
45 *
46 * @author Florian Wininger
47 */
48 public class TmfXmlCondition {
49
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;
55
56 private enum LogicalOperator {
57 NONE,
58 NOT,
59 AND,
60 OR,
61 }
62
63 private enum ConditionOperator {
64 NONE,
65 EQ,
66 NE,
67 GE,
68 GT,
69 LE,
70 LT
71 }
72
73 /**
74 * Constructor
75 *
76 * @param modelFactory
77 * The factory used to create XML model elements
78 * @param node
79 * The XML root of this condition
80 * @param container
81 * The state system container this condition belongs to
82 */
83 public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
84 fContainer = container;
85
86 Element rootNode = node;
87 /* Process the conditions: in each case, only process Element nodes */
88 List<@Nullable Element> childElements = XmlUtils.getChildElements(rootNode);
89
90 /*
91 * If the node is an if, take the child as the root condition
92 *
93 * FIXME: Maybe the caller should do this instead.
94 */
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$
98 }
99 rootNode = childElements.get(0);
100 childElements = XmlUtils.getChildElements(rootNode);
101 }
102
103 if (rootNode == null) {
104 throw new IllegalArgumentException();
105 }
106
107 switch (rootNode.getNodeName()) {
108 case TmfXmlStrings.CONDITION:
109 fOperator = LogicalOperator.NONE;
110 /* Read comparison type */
111 String equationType = rootNode.getAttribute(TmfXmlStrings.OPERATOR);
112
113 switch (equationType) {
114 case TmfXmlStrings.EQ:
115 fConditionOperator = ConditionOperator.EQ;
116 break;
117 case TmfXmlStrings.NE:
118 fConditionOperator = ConditionOperator.NE;
119 break;
120 case TmfXmlStrings.GE:
121 fConditionOperator = ConditionOperator.GE;
122 break;
123 case TmfXmlStrings.GT:
124 fConditionOperator = ConditionOperator.GT;
125 break;
126 case TmfXmlStrings.LE:
127 fConditionOperator = ConditionOperator.LE;
128 break;
129 case TmfXmlStrings.LT:
130 fConditionOperator = ConditionOperator.LT;
131 break;
132 case TmfXmlStrings.NULL:
133 fConditionOperator = ConditionOperator.EQ;
134 break;
135 default:
136 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
137 }
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();
142 }
143
144 /*
145 * A state value is either preceded by an eventField or a number of
146 * state attributes
147 */
148 @Nullable Element firstChild = childElements.get(0);
149 if (firstChild == null) {
150 throw new IllegalStateException();
151 }
152
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();
157 }
158 fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, attribute);
159 } else {
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$
164 }
165 ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
166 attributes.add(attribute);
167 }
168 fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, attributes);
169 }
170 break;
171 case TmfXmlStrings.NOT:
172 fOperator = LogicalOperator.NOT;
173 fStateValue = null;
174 fConditionOperator = ConditionOperator.NONE;
175 Element element = childElements.get(0);
176 if (element == null) {
177 throw new IllegalArgumentException();
178 }
179 fConditions.add(modelFactory.createCondition(element, fContainer));
180 break;
181 case TmfXmlStrings.AND:
182 fOperator = LogicalOperator.AND;
183 fStateValue = null;
184 fConditionOperator = ConditionOperator.NONE;
185 for (Element condition : childElements) {
186 if (condition == null) {
187 continue;
188 }
189 fConditions.add(modelFactory.createCondition(condition, fContainer));
190 }
191 break;
192 case TmfXmlStrings.OR:
193 fOperator = LogicalOperator.OR;
194 fStateValue = null;
195 fConditionOperator = ConditionOperator.NONE;
196 for (Element condition : childElements) {
197 if (condition == null) {
198 continue;
199 }
200 fConditions.add(modelFactory.createCondition(condition, fContainer));
201 }
202 break;
203 default:
204 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
205 }
206 }
207
208 /**
209 * Test the result of the condition for an event
210 *
211 * @param 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
216 */
217 public boolean testForEvent(ITmfEvent event) throws AttributeNotFoundException {
218 ITmfStateSystem ss = fContainer.getStateSystem();
219 /*
220 * The condition is either the equality check of a state value or a
221 * boolean operation on other conditions
222 */
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);
228 /*
229 * When verifying a condition, the state attribute must exist,
230 * if it does not, the query is not valid, we stop the condition
231 * check
232 */
233 if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
234 throw new AttributeNotFoundException(ss.getSSID() + " Attribute:" + attribute); //$NON-NLS-1$
235 }
236 }
237
238 /* Get the value to compare to from the XML file */
239 ITmfStateValue valueXML;
240 valueXML = filter.getValue(event);
241
242 /*
243 * The actual value: it can be either queried in the state system or
244 * found in the event
245 */
246 ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) :
247 filter.getEventFieldValue(event);
248 if (valueState == null) {
249 throw new IllegalStateException();
250 }
251
252 return compare(valueState, valueXML, fConditionOperator);
253
254 } else if (!fConditions.isEmpty()) {
255 /* Verify a condition tree */
256 switch (fOperator) {
257 case AND:
258 for (TmfXmlCondition childCondition : fConditions) {
259 if (!childCondition.testForEvent(event)) {
260 return false;
261 }
262 }
263 return true;
264 case NONE:
265 break;
266 case NOT:
267 return !fConditions.get(0).testForEvent(event);
268 case OR:
269 for (TmfXmlCondition childCondition : fConditions) {
270 if (childCondition.testForEvent(event)) {
271 return true;
272 }
273 }
274 return false;
275 default:
276 break;
277
278 }
279 } else {
280 throw new IllegalStateException("TmfXmlCondition: the condition should be either a state value or be the result of a condition tree"); //$NON-NLS-1$
281 }
282 return true;
283 }
284
285 @Override
286 public String toString() {
287 return "TmfXmlCondition: " + fOperator + " on " + fConditions; //$NON-NLS-1$ //$NON-NLS-2$
288 }
289
290 /**
291 * Compare two ITmfStateValues based on the given comparison operator
292 *
293 * @param source
294 * the state value to compare to
295 * @param dest
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
300 */
301 public boolean compare(ITmfStateValue source, ITmfStateValue dest, ConditionOperator comparisonOperator) {
302 switch (comparisonOperator) {
303 case EQ:
304 return (source.compareTo(dest) == 0);
305 case NE:
306 return (source.compareTo(dest) != 0);
307 case GE:
308 return (source.compareTo(dest) >= 0);
309 case GT:
310 return (source.compareTo(dest) > 0);
311 case LE:
312 return (source.compareTo(dest) <= 0);
313 case LT:
314 return (source.compareTo(dest) < 0);
315 case NONE:
316 default:
317 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
318 }
319
320 }
321
322 }
This page took 0.044821 seconds and 5 git commands to generate.