tmf : Fix the xml condition multiple problem
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.core / src / org / eclipse / tracecompass / tmf / analysis / xml / core / model / TmfXmlCondition.java
CommitLineData
0f7276b6 1/*******************************************************************************
b39b8c5b 2 * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal and others
0f7276b6
GB
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
5ddeee68 11 * Naser Ezzati - Add the comparison operators
e13bd4cd 12 * Patrick Tasse - Add message to exceptions
b39b8c5b 13 * Jean-Christian Kouame - Add comparison between two state values
0f7276b6
GB
14 ******************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
0f7276b6
GB
17
18import java.util.ArrayList;
19import java.util.List;
20
12685851 21import org.eclipse.jdt.annotation.Nullable;
b39b8c5b 22import org.eclipse.tracecompass.common.core.NonNullUtils;
e894a508
AM
23import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
24import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
25import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
2bdf0193
AM
26import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
27import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
28import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
29import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
0f7276b6
GB
30import org.w3c.dom.Element;
31
32/**
1d7e62f9 33 * This Class implement a condition tree in the XML-defined state system.
0f7276b6
GB
34 *
35 * <pre>
36 * example:
37 * <and>
38 * <condition>
39 * <stateAttribute type="location" value="CurrentThread" />
40 * <stateAttribute type="constant" value="System_call" />
41 * <stateValue type="null" />
42 * </condition>
43 * <condition>
b39b8c5b
JCK
44 * <stateValue type="long" value="2" />
45 * <stateValue type="long" value="5" />
0f7276b6
GB
46 * </condition>
47 * </and>
48 * </pre>
49 *
50 * @author Florian Wininger
51 */
52public class TmfXmlCondition {
53
54 private final List<TmfXmlCondition> fConditions = new ArrayList<>();
b39b8c5b 55 private final List<ITmfXmlStateValue> fStateValues;
5ddeee68 56 private final LogicalOperator fOperator;
1d7e62f9 57 private final IXmlStateSystemContainer fContainer;
5ddeee68 58 private final ConditionOperator fConditionOperator;
0f7276b6 59
5ddeee68 60 private enum LogicalOperator {
0f7276b6
GB
61 NONE,
62 NOT,
63 AND,
64 OR,
65 }
66
5ddeee68
NE
67 private enum ConditionOperator {
68 NONE,
69 EQ,
70 NE,
71 GE,
72 GT,
73 LE,
74 LT
75 }
76
0f7276b6
GB
77 /**
78 * Constructor
79 *
1d7e62f9
GB
80 * @param modelFactory
81 * The factory used to create XML model elements
0f7276b6
GB
82 * @param node
83 * The XML root of this condition
1d7e62f9
GB
84 * @param container
85 * The state system container this condition belongs to
0f7276b6 86 */
1d7e62f9
GB
87 public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
88 fContainer = container;
0f7276b6
GB
89
90 Element rootNode = node;
91 /* Process the conditions: in each case, only process Element nodes */
4c4e2816 92 List<@Nullable Element> childElements = XmlUtils.getChildElements(rootNode);
b39b8c5b 93 final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
0f7276b6
GB
94
95 /*
96 * If the node is an if, take the child as the root condition
97 *
98 * FIXME: Maybe the caller should do this instead.
99 */
100 if (node.getNodeName().equals(TmfXmlStrings.IF)) {
101 if (childElements.isEmpty()) {
b39b8c5b 102 throw new IllegalArgumentException("TmfXmlCondition constructor: IF node with no child element"); //$NON-NLS-1$
0f7276b6 103 }
b39b8c5b 104 rootNode = firstElement;
0f7276b6
GB
105 childElements = XmlUtils.getChildElements(rootNode);
106 }
4c4e2816 107
0f7276b6
GB
108 switch (rootNode.getNodeName()) {
109 case TmfXmlStrings.CONDITION:
1010de5e
JCK
110 int size = rootNode.getElementsByTagName(TmfXmlStrings.STATE_VALUE).getLength();
111 fStateValues = new ArrayList<>(size);
5ddeee68 112 fOperator = LogicalOperator.NONE;
b39b8c5b
JCK
113 if (size == 1) {
114 fConditionOperator = getConditionOperator(rootNode);
115 getStateValuesForXmlCondition(modelFactory, NonNullUtils.checkNotNull(childElements));
0f7276b6 116 } else {
b39b8c5b
JCK
117 fConditionOperator = ConditionOperator.EQ;
118 fStateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(0)), fContainer, new ArrayList<ITmfXmlStateAttribute>()));
119 fStateValues.add(modelFactory.createStateValue(NonNullUtils.checkNotNull(childElements.get(1)), fContainer, new ArrayList<ITmfXmlStateAttribute>()));
0f7276b6
GB
120 }
121 break;
122 case TmfXmlStrings.NOT:
1010de5e 123 fStateValues = new ArrayList<>();
5ddeee68 124 fOperator = LogicalOperator.NOT;
5ddeee68 125 fConditionOperator = ConditionOperator.NONE;
b39b8c5b 126 Element element = firstElement;
12685851 127 fConditions.add(modelFactory.createCondition(element, fContainer));
0f7276b6
GB
128 break;
129 case TmfXmlStrings.AND:
1010de5e 130 fStateValues = new ArrayList<>();
5ddeee68 131 fOperator = LogicalOperator.AND;
5ddeee68 132 fConditionOperator = ConditionOperator.NONE;
0f7276b6 133 for (Element condition : childElements) {
12685851
GB
134 if (condition == null) {
135 continue;
136 }
1d7e62f9 137 fConditions.add(modelFactory.createCondition(condition, fContainer));
0f7276b6
GB
138 }
139 break;
140 case TmfXmlStrings.OR:
1010de5e 141 fStateValues = new ArrayList<>();
5ddeee68 142 fOperator = LogicalOperator.OR;
5ddeee68 143 fConditionOperator = ConditionOperator.NONE;
0f7276b6 144 for (Element condition : childElements) {
12685851
GB
145 if (condition == null) {
146 continue;
147 }
1d7e62f9 148 fConditions.add(modelFactory.createCondition(condition, fContainer));
0f7276b6
GB
149 }
150 break;
151 default:
152 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
153 }
154 }
155
b39b8c5b
JCK
156 private void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory, List<@Nullable Element> childElements) {
157 Element stateValueElement = NonNullUtils.checkNotNull(childElements.remove(childElements.size() - 1));
158 /*
159 * A state value is either preceded by an eventField or a number of
160 * state attributes
161 */
162 final Element firstElement = NonNullUtils.checkNotNull(childElements.get(0));
163 if (childElements.size() == 1 && firstElement.getNodeName().equals(TmfXmlStrings.ELEMENT_FIELD)) {
164 String attribute = firstElement.getAttribute(TmfXmlStrings.NAME);
165 fStateValues.add(modelFactory.createStateValue(stateValueElement, fContainer, attribute));
166 } else {
167 List<ITmfXmlStateAttribute> attributes = new ArrayList<>();
168 for (Element element : childElements) {
169 if (element == null) {
170 throw new NullPointerException("There should be at list one element"); //$NON-NLS-1$
171 }
172 if (!element.getNodeName().equals(TmfXmlStrings.STATE_ATTRIBUTE)) {
173 throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
174 }
175 ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
176 attributes.add(attribute);
177 }
178 fStateValues.add(modelFactory.createStateValue(stateValueElement, fContainer, attributes));
179 }
180 }
181
182 private static ConditionOperator getConditionOperator(Element rootNode) {
183 String equationType = rootNode.getAttribute(TmfXmlStrings.OPERATOR);
184 switch (equationType) {
185 case TmfXmlStrings.EQ:
186 return ConditionOperator.EQ;
187 case TmfXmlStrings.NE:
188 return ConditionOperator.NE;
189 case TmfXmlStrings.GE:
190 return ConditionOperator.GE;
191 case TmfXmlStrings.GT:
192 return ConditionOperator.GT;
193 case TmfXmlStrings.LE:
194 return ConditionOperator.LE;
195 case TmfXmlStrings.LT:
196 return ConditionOperator.LT;
197 case TmfXmlStrings.NULL:
198 return ConditionOperator.EQ;
199 default:
200 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
201 }
202 }
203
0f7276b6
GB
204 /**
205 * Test the result of the condition for an event
206 *
207 * @param event
208 * The event on which to test the condition
209 * @return Whether the condition is true or not
210 * @throws AttributeNotFoundException
211 * The state attribute was not found
b39b8c5b 212 * @since 1.0
0f7276b6 213 */
12685851 214 public boolean testForEvent(ITmfEvent event) throws AttributeNotFoundException {
1d7e62f9 215 ITmfStateSystem ss = fContainer.getStateSystem();
b39b8c5b
JCK
216 if (!fStateValues.isEmpty()) {
217 return testForEvent(event, NonNullUtils.checkNotNull(ss));
0f7276b6
GB
218 } else if (!fConditions.isEmpty()) {
219 /* Verify a condition tree */
220 switch (fOperator) {
221 case AND:
222 for (TmfXmlCondition childCondition : fConditions) {
223 if (!childCondition.testForEvent(event)) {
224 return false;
225 }
226 }
227 return true;
228 case NONE:
229 break;
230 case NOT:
231 return !fConditions.get(0).testForEvent(event);
232 case OR:
233 for (TmfXmlCondition childCondition : fConditions) {
234 if (childCondition.testForEvent(event)) {
235 return true;
236 }
237 }
238 return false;
239 default:
240 break;
241
242 }
0f7276b6
GB
243 }
244 return true;
245 }
246
b39b8c5b
JCK
247 private boolean testForEvent(ITmfEvent event, ITmfStateSystem ss) throws AttributeNotFoundException {
248 /*
249 * The condition is either the equality check of a state value or a
250 * boolean operation on other conditions
251 */
252 if (fStateValues.size() == 1) {
253 ITmfXmlStateValue filter = fStateValues.get(0);
254 int quark = IXmlStateSystemContainer.ROOT_QUARK;
255 for (ITmfXmlStateAttribute attribute : filter.getAttributes()) {
256 quark = attribute.getAttributeQuark(event, quark);
257 /*
258 * When verifying a condition, the state attribute must exist,
259 * if it does not, the query is not valid, we stop the condition
260 * check
261 */
262 if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
263 throw new AttributeNotFoundException(ss.getSSID() + " Attribute:" + attribute); //$NON-NLS-1$
264 }
265 }
266
267 /*
268 * The actual value: it can be either queried in the state system or
269 * found in the event
270 */
271 ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) : filter.getEventFieldValue(event);
272 if (valueState == null) {
273 throw new IllegalStateException("TmfXmlCondition : The state value does not exist in the state system"); //$NON-NLS-1$
274 }
275
276 /* Get the value to compare to from the XML file */
277 ITmfStateValue valueXML;
278 valueXML = filter.getValue(event);
279 return compare(valueState, valueXML, fConditionOperator);
280 }
281 /* Get the two values needed for the comparison */
282 ITmfStateValue valuesXML1 = fStateValues.get(0).getValue(event);
283 ITmfStateValue valuesXML2 = fStateValues.get(1).getValue(event);
284 return valuesXML1.equals(valuesXML2);
285 }
286
446598f9
GB
287 @Override
288 public String toString() {
289 return "TmfXmlCondition: " + fOperator + " on " + fConditions; //$NON-NLS-1$ //$NON-NLS-2$
290 }
291
5ddeee68
NE
292 /**
293 * Compare two ITmfStateValues based on the given comparison operator
294 *
295 * @param source
296 * the state value to compare to
297 * @param dest
298 * the state value to be compared with
299 * @param comparisonOperator
300 * the operator to compare the inputs
301 * @return the boolean result of the comparison
302 */
303 public boolean compare(ITmfStateValue source, ITmfStateValue dest, ConditionOperator comparisonOperator) {
5ddeee68 304 switch (comparisonOperator) {
b39b8c5b 305 //TODO The comparison operator should have a compareHelper that calls compare
5ddeee68
NE
306 case EQ:
307 return (source.compareTo(dest) == 0);
308 case NE:
309 return (source.compareTo(dest) != 0);
310 case GE:
311 return (source.compareTo(dest) >= 0);
312 case GT:
313 return (source.compareTo(dest) > 0);
314 case LE:
315 return (source.compareTo(dest) <= 0);
316 case LT:
317 return (source.compareTo(dest) < 0);
318 case NONE:
319 default:
320 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
321 }
5ddeee68 322 }
0f7276b6 323}
This page took 0.100116 seconds and 5 git commands to generate.