ss: Mark ITmfStateSystem#queryOngoingState as @NonNull
[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 and others
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 * Jean-Christian Kouame - Add comparison between two state values
14 ******************************************************************************/
15
16 package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
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;
31
32 /**
33 * This Class implement a condition tree in the XML-defined state system.
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>
44 * <stateValue type="long" value="2" />
45 * <stateValue type="long" value="5" />
46 * </condition>
47 * </and>
48 * </pre>
49 *
50 * @author Florian Wininger
51 */
52 public class TmfXmlCondition {
53
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;
59
60 private enum LogicalOperator {
61 NONE,
62 NOT,
63 AND,
64 OR,
65 }
66
67 private enum ConditionOperator {
68 NONE,
69 EQ,
70 NE,
71 GE,
72 GT,
73 LE,
74 LT
75 }
76
77 /**
78 * Constructor
79 *
80 * @param modelFactory
81 * The factory used to create XML model elements
82 * @param node
83 * The XML root of this condition
84 * @param container
85 * The state system container this condition belongs to
86 */
87 public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
88 fContainer = container;
89
90 Element rootNode = node;
91 /* Process the conditions: in each case, only process Element nodes */
92 List<@Nullable Element> childElements = XmlUtils.getChildElements(rootNode);
93
94 /*
95 * If the node is an if, take the child as the root condition
96 *
97 * FIXME: Maybe the caller should do this instead.
98 */
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$
102 }
103 rootNode = NonNullUtils.checkNotNull(childElements.get(0));
104 childElements = XmlUtils.getChildElements(rootNode);
105 }
106
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;
112 if (size == 1) {
113 fConditionOperator = getConditionOperator(rootNode);
114 getStateValuesForXmlCondition(modelFactory, NonNullUtils.checkNotNull(childElements));
115 } else {
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>()));
121 }
122 break;
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));
129 break;
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) {
136 continue;
137 }
138 fConditions.add(modelFactory.createCondition(condition, fContainer));
139 }
140 break;
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) {
147 continue;
148 }
149 fConditions.add(modelFactory.createCondition(condition, fContainer));
150 }
151 break;
152 default:
153 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
154 }
155 }
156
157 private void getStateValuesForXmlCondition(ITmfXmlModelFactory modelFactory, List<@Nullable Element> childElements) {
158 Element stateValueElement = NonNullUtils.checkNotNull(childElements.remove(childElements.size() - 1));
159 /*
160 * A state value is either preceded by an eventField or a number of
161 * state attributes
162 */
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));
167 } else {
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$
172 }
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$
175 }
176 ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
177 attributes.add(attribute);
178 }
179 fStateValues.add(modelFactory.createStateValue(stateValueElement, fContainer, attributes));
180 }
181 }
182
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;
200 default:
201 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
202 }
203 }
204
205 /**
206 * Test the result of the condition for an event
207 *
208 * @param 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
213 * @since 1.0
214 */
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 */
221 switch (fOperator) {
222 case AND:
223 for (TmfXmlCondition childCondition : fConditions) {
224 if (!childCondition.testForEvent(event)) {
225 return false;
226 }
227 }
228 return true;
229 case NONE:
230 break;
231 case NOT:
232 return !fConditions.get(0).testForEvent(event);
233 case OR:
234 for (TmfXmlCondition childCondition : fConditions) {
235 if (childCondition.testForEvent(event)) {
236 return true;
237 }
238 }
239 return false;
240 default:
241 break;
242
243 }
244 }
245 return true;
246 }
247
248 private boolean testForEvent(ITmfEvent event, ITmfStateSystem ss) throws AttributeNotFoundException {
249 /*
250 * The condition is either the equality check of a state value or a
251 * boolean operation on other conditions
252 */
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);
258 /*
259 * When verifying a condition, the state attribute must exist,
260 * if it does not, the query is not valid, we stop the condition
261 * check
262 */
263 if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
264 throw new AttributeNotFoundException(ss.getSSID() + " Attribute:" + attribute); //$NON-NLS-1$
265 }
266 }
267
268 /*
269 * The actual value: it can be either queried in the state system or
270 * found in the event
271 */
272 ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) : filter.getEventFieldValue(event);
273
274 /* Get the value to compare to from the XML file */
275 ITmfStateValue valueXML;
276 valueXML = filter.getValue(event);
277 return compare(valueState, valueXML, fConditionOperator);
278 }
279 /* Get the two values needed for the comparison */
280 ITmfStateValue valuesXML1 = fStateValues.get(0).getValue(event);
281 ITmfStateValue valuesXML2 = fStateValues.get(1).getValue(event);
282 return valuesXML1.equals(valuesXML2);
283 }
284
285 @Override
286 public String toString() {
287 StringBuilder output = new StringBuilder("TmfXmlCondition: "); //$NON-NLS-1$
288 if (fOperator != LogicalOperator.NONE) {
289 output.append(fOperator).append(" on ").append(fConditions); //$NON-NLS-1$
290 } else {
291 output.append(fConditionOperator).append(" {").append(fStateValues.get(0)); //$NON-NLS-1$
292 if (fStateValues.size() == 2) {
293 output.append(", ").append(fStateValues.get(1)); //$NON-NLS-1$
294 }
295 output.append("}"); //$NON-NLS-1$
296 }
297 return output.toString();
298 }
299
300 /**
301 * Compare two ITmfStateValues based on the given comparison operator
302 *
303 * @param source
304 * the state value to compare to
305 * @param dest
306 * the state value to be compared with
307 * @param comparisonOperator
308 * the operator to compare the inputs
309 * @return the boolean result of the comparison
310 */
311 public boolean compare(ITmfStateValue source, ITmfStateValue dest, ConditionOperator comparisonOperator) {
312 switch (comparisonOperator) {
313 //TODO The comparison operator should have a compareHelper that calls compare
314 case EQ:
315 return (source.compareTo(dest) == 0);
316 case NE:
317 return (source.compareTo(dest) != 0);
318 case GE:
319 return (source.compareTo(dest) >= 0);
320 case GT:
321 return (source.compareTo(dest) > 0);
322 case LE:
323 return (source.compareTo(dest) <= 0);
324 case LT:
325 return (source.compareTo(dest) < 0);
326 case NONE:
327 default:
328 throw new IllegalArgumentException("TmfXmlCondition: invalid comparison operator."); //$NON-NLS-1$
329 }
330 }
331 }
This page took 0.039021 seconds and 5 git commands to generate.