TMF: Refactor XML model code, using factories to re-use element parsers
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.analysis.xml.core / src / org / eclipse / linuxtools / tmf / analysis / xml / core / model / TmfXmlCondition.java
1 /*******************************************************************************
2 * Copyright (c) 2014 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 ******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.analysis.xml.core.model;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.linuxtools.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
20 import org.eclipse.linuxtools.tmf.analysis.xml.core.module.XmlUtils;
21 import org.eclipse.linuxtools.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
23 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
24 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
25 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
26 import org.w3c.dom.Element;
27
28 /**
29 * This Class implement a condition tree in the XML-defined state system.
30 *
31 * <pre>
32 * example:
33 * <and>
34 * <condition>
35 * <stateAttribute type="location" value="CurrentThread" />
36 * <stateAttribute type="constant" value="System_call" />
37 * <stateValue type="null" />
38 * </condition>
39 * <condition>
40 * </condition>
41 * </and>
42 * </pre>
43 *
44 * @author Florian Wininger
45 */
46 public class TmfXmlCondition {
47
48 private final List<TmfXmlCondition> fConditions = new ArrayList<>();
49 private final ITmfXmlStateValue fStateValue;
50 private final ConditionOperator fOperator;
51 private final IXmlStateSystemContainer fContainer;
52
53 private enum ConditionOperator {
54 NONE,
55 NOT,
56 AND,
57 OR,
58 }
59
60 /**
61 * Constructor
62 *
63 * @param modelFactory
64 * The factory used to create XML model elements
65 * @param node
66 * The XML root of this condition
67 * @param container
68 * The state system container this condition belongs to
69 */
70 public TmfXmlCondition(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer container) {
71 fContainer = container;
72
73 Element rootNode = node;
74 /* Process the conditions: in each case, only process Element nodes */
75 List<Element> childElements = XmlUtils.getChildElements(rootNode);
76
77 /*
78 * If the node is an if, take the child as the root condition
79 *
80 * FIXME: Maybe the caller should do this instead.
81 */
82 if (node.getNodeName().equals(TmfXmlStrings.IF)) {
83 if (childElements.isEmpty()) {
84 throw new IllegalArgumentException("TmfXmlCondition constructor: IF node has no child element"); //$NON-NLS-1$
85 }
86 rootNode = childElements.get(0);
87 childElements = XmlUtils.getChildElements(rootNode);
88 }
89
90 switch (rootNode.getNodeName()) {
91 case TmfXmlStrings.CONDITION:
92 fOperator = ConditionOperator.NONE;
93 /* The last element is a state value node */
94 Element stateValueElement = childElements.remove(childElements.size() - 1);
95
96 /*
97 * A state value is either preceded by an eventField or a number of
98 * state attributes
99 */
100 if (childElements.size() == 1 && childElements.get(0).getNodeName().equals(TmfXmlStrings.ELEMENT_FIELD)) {
101 fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, childElements.get(0).getAttribute(TmfXmlStrings.NAME));
102 } else {
103 List<ITmfXmlStateAttribute> attributes = new ArrayList<>();
104 for (Element element : childElements) {
105 if (!element.getNodeName().equals(TmfXmlStrings.STATE_ATTRIBUTE)) {
106 throw new IllegalArgumentException("TmfXmlCondition: a condition either has a eventField element or a number of TmfXmlStateAttribute elements before the state value"); //$NON-NLS-1$
107 }
108 ITmfXmlStateAttribute attribute = modelFactory.createStateAttribute(element, fContainer);
109 attributes.add(attribute);
110 }
111 fStateValue = modelFactory.createStateValue(stateValueElement, fContainer, attributes);
112 }
113 break;
114 case TmfXmlStrings.NOT:
115 fOperator = ConditionOperator.NOT;
116 fStateValue = null;
117 fConditions.add(modelFactory.createCondition(childElements.get(0), fContainer));
118 break;
119 case TmfXmlStrings.AND:
120 fOperator = ConditionOperator.AND;
121 fStateValue = null;
122 for (Element condition : childElements) {
123 fConditions.add(modelFactory.createCondition(condition, fContainer));
124 }
125 break;
126 case TmfXmlStrings.OR:
127 fOperator = ConditionOperator.OR;
128 fStateValue = null;
129 for (Element condition : childElements) {
130 fConditions.add(modelFactory.createCondition(condition, fContainer));
131 }
132 break;
133 default:
134 throw new IllegalArgumentException("TmfXmlCondition constructor: XML node is of the wrong type"); //$NON-NLS-1$
135 }
136 }
137
138 /**
139 * Test the result of the condition for an event
140 *
141 * @param event
142 * The event on which to test the condition
143 * @return Whether the condition is true or not
144 * @throws AttributeNotFoundException
145 * The state attribute was not found
146 */
147 public boolean testForEvent(@NonNull ITmfEvent event) throws AttributeNotFoundException {
148 ITmfStateSystem ss = fContainer.getStateSystem();
149 /*
150 * The condition is either the equality check of a state value or a
151 * boolean operation on other conditions
152 */
153 if (fStateValue != null) {
154 ITmfXmlStateValue filter = fStateValue;
155 int quark = IXmlStateSystemContainer.ROOT_QUARK;
156 for (ITmfXmlStateAttribute attribute : filter.getAttributes()) {
157 quark = attribute.getAttributeQuark(event, quark);
158 /*
159 * When verifying a condition, the state attribute must exist,
160 * if it does not, the query is not valid, we stop the condition
161 * check
162 */
163 if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
164 throw new AttributeNotFoundException();
165 }
166 }
167
168 /* Get the value to compare to from the XML file */
169 ITmfStateValue valueXML;
170 valueXML = filter.getValue(event);
171
172 /*
173 * The actual value: it can be either queried in the state system or
174 * found in the event
175 */
176 ITmfStateValue valueState = (quark != IXmlStateSystemContainer.ROOT_QUARK) ? ss.queryOngoingState(quark) :
177 filter.getEventFieldValue(event);
178
179 return valueXML.equals(valueState);
180
181 } else if (!fConditions.isEmpty()) {
182 /* Verify a condition tree */
183 switch (fOperator) {
184 case AND:
185 for (TmfXmlCondition childCondition : fConditions) {
186 if (!childCondition.testForEvent(event)) {
187 return false;
188 }
189 }
190 return true;
191 case NONE:
192 break;
193 case NOT:
194 return !fConditions.get(0).testForEvent(event);
195 case OR:
196 for (TmfXmlCondition childCondition : fConditions) {
197 if (childCondition.testForEvent(event)) {
198 return true;
199 }
200 }
201 return false;
202 default:
203 break;
204
205 }
206 } else {
207 throw new IllegalStateException("TmfXmlCondition: the condition should be either a state value or be the result of a condition tree"); //$NON-NLS-1$
208 }
209 return true;
210 }
211
212 }
This page took 0.034506 seconds and 5 git commands to generate.