aa31e945d6914c1a8d8c57698c2ee01aa889e42e
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.core / src / org / eclipse / tracecompass / internal / tmf / analysis / xml / core / model / TmfXmlStateAttribute.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 ******************************************************************************/
12
13 package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model;
14
15 import java.util.LinkedList;
16 import java.util.List;
17
18 import org.eclipse.jdt.annotation.Nullable;
19 import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
20 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
21
22 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
23 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
24 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
25 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
26 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
27 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
28 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
29 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
30 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
31 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
32 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
33 import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
34 import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
35 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
36 import org.w3c.dom.Element;
37
38 /**
39 * This Class implements a single attribute value in the XML-defined state
40 * system.
41 *
42 * <pre>
43 * Examples:
44 * <stateAttribute type="constant" value="Threads" />
45 * <stateAttribute type="query" />
46 * <stateAttribute type="constant" value="CPUs" />
47 * <stateAttribute type="eventField" value="cpu" />
48 * <stateAttribute type="constant" value="Current_thread" />
49 * </attribute>
50 * </pre>
51 *
52 * @author Florian Wininger
53 */
54 public abstract class TmfXmlStateAttribute implements ITmfXmlStateAttribute {
55
56 private enum StateAttributeType {
57 NONE,
58 CONSTANT,
59 EVENTFIELD,
60 QUERY,
61 LOCATION,
62 SELF,
63 EVENTNAME
64 }
65
66 private final String CURRENT_STATE = "#currentState"; //$NON-NLS-1$
67
68 private final String CURRENT_SCENARIO = "#CurrentScenario"; //$NON-NLS-1$
69
70 /** Type of attribute */
71 private final StateAttributeType fType;
72
73 /** Attribute's name */
74 private final @Nullable String fName;
75
76 /** List of attributes for a query */
77 private final List<ITmfXmlStateAttribute> fQueryList = new LinkedList<>();
78
79 private final IXmlStateSystemContainer fContainer;
80
81 /**
82 * Constructor
83 *
84 * @param modelFactory
85 * The factory used to create XML model elements
86 * @param attribute
87 * XML element of the attribute
88 * @param container
89 * The state system container this state attribute belongs to
90 */
91 protected TmfXmlStateAttribute(ITmfXmlModelFactory modelFactory, Element attribute, IXmlStateSystemContainer container) {
92 fContainer = container;
93
94 switch (attribute.getAttribute(TmfXmlStrings.TYPE)) {
95 case TmfXmlStrings.TYPE_CONSTANT:
96 fType = StateAttributeType.CONSTANT;
97 fName = getAttributeName(attribute);
98 break;
99 case TmfXmlStrings.EVENT_FIELD:
100 fType = StateAttributeType.EVENTFIELD;
101 fName = getAttributeName(attribute);
102 break;
103 case TmfXmlStrings.TYPE_LOCATION:
104 fType = StateAttributeType.LOCATION;
105 fName = getAttributeName(attribute);
106 break;
107 case TmfXmlStrings.TYPE_QUERY:
108 List<@Nullable Element> childElements = XmlUtils.getChildElements(attribute);
109 for (Element subAttributeNode : childElements) {
110 if (subAttributeNode == null) {
111 continue;
112 }
113 ITmfXmlStateAttribute subAttribute = modelFactory.createStateAttribute(subAttributeNode, fContainer);
114 fQueryList.add(subAttribute);
115 }
116 fType = StateAttributeType.QUERY;
117 fName = null;
118 break;
119 case TmfXmlStrings.TYPE_EVENT_NAME:
120 fType = StateAttributeType.EVENTNAME;
121 fName = getAttributeName(attribute);
122 break;
123 case TmfXmlStrings.NULL:
124 fType = StateAttributeType.NONE;
125 fName = null;
126 break;
127 case TmfXmlStrings.TYPE_SELF:
128 fType = StateAttributeType.SELF;
129 fName = null;
130 break;
131 default:
132 throw new IllegalArgumentException("TmfXmlStateAttribute constructor: The XML element is not of the right type"); //$NON-NLS-1$
133 }
134 }
135
136 private String getAttributeName(Element attribute) {
137 return fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)).intern();
138 }
139
140 @Override
141 public int getAttributeQuark(int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) {
142 return getAttributeQuark(null, startQuark, scenarioInfo);
143 }
144
145 /**
146 * Basic quark-retrieving method. Pass an attribute in parameter as an array
147 * of strings, the matching quark will be returned. If the attribute does
148 * not exist, it will add the quark to the state system if the context
149 * allows it.
150 *
151 * See {@link ITmfStateSystemBuilder#getQuarkAbsoluteAndAdd(String...)}
152 *
153 * @param path
154 * Full path to the attribute
155 * @return The quark for this attribute
156 * @throws AttributeNotFoundException
157 * The attribute does not exist and cannot be added
158 */
159 protected abstract int getQuarkAbsoluteAndAdd(String... path) throws AttributeNotFoundException;
160
161 /**
162 * Quark-retrieving method, but the attribute is queried starting from the
163 * startNodeQuark. If the attribute does not exist, it will add it to the
164 * state system if the context allows it.
165 *
166 * See {@link ITmfStateSystemBuilder#getQuarkRelativeAndAdd(int, String...)}
167 *
168 * @param startNodeQuark
169 * The quark of the attribute from which 'path' originates.
170 * @param path
171 * Relative path to the attribute
172 * @return The quark for this attribute
173 * @throws AttributeNotFoundException
174 * The attribute does not exist and cannot be added
175 */
176 protected abstract int getQuarkRelativeAndAdd(int startNodeQuark, String... path) throws AttributeNotFoundException;
177
178 /**
179 * Get the state system associated with this attribute's container
180 *
181 * @return The state system associated with this state attribute
182 */
183 protected @Nullable ITmfStateSystem getStateSystem() {
184 return fContainer.getStateSystem();
185 }
186
187 @Override
188 public int getAttributeQuark(@Nullable ITmfEvent event, int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) {
189 ITmfStateSystem ss = getStateSystem();
190 if (ss == null) {
191 throw new IllegalStateException("The state system hasn't been initialized yet"); //$NON-NLS-1$
192 }
193 String name = nullToEmptyString(fName);
194 if (name.length() > 0 && name.charAt(0) == '#' && scenarioInfo == null) {
195 throw new IllegalStateException("XML Attribute needs " + fName + " but the data is not available."); //$NON-NLS-1$//$NON-NLS-2$
196 }
197 name = name.equals(CURRENT_STATE) ? checkNotNull(scenarioInfo).getActiveState()
198 : fName;
199
200 try {
201 switch (fType) {
202 case CONSTANT: {
203 int quark;
204 if (name == null) {
205 throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$
206 }
207 if (name.equals(CURRENT_SCENARIO)) {
208 return checkNotNull(scenarioInfo).getQuark();
209 }
210 if (startQuark == IXmlStateSystemContainer.ROOT_QUARK) {
211 quark = getQuarkAbsoluteAndAdd(name);
212 } else {
213 quark = getQuarkRelativeAndAdd(startQuark, name);
214 }
215 return quark;
216 }
217 case EVENTFIELD: {
218 int quark = IXmlStateSystemContainer.ERROR_QUARK;
219 if (event == null) {
220 Activator.logWarning("XML State attribute: looking for an event field, but event is null"); //$NON-NLS-1$
221 return quark;
222 }
223 if (name == null) {
224 throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$
225 }
226 /* First, look for a field with the given name */
227 ITmfEventField field = event.getContent().getField(name);
228 /* Field not found, see if it is a special case field */
229 if (field == null) {
230 if (name.equalsIgnoreCase(TmfXmlStrings.CPU)) {
231 /* See if the event advertises a CPU aspect */
232 Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(
233 event.getTrace(), TmfCpuAspect.class, event);
234 if (cpu != null) {
235 return getQuarkRelativeAndAdd(startQuark, cpu.toString());
236 }
237 }
238 return IXmlStateSystemContainer.ERROR_QUARK;
239 }
240 Object fieldValue = field.getValue();
241
242 if (fieldValue instanceof String) {
243 String fieldString = (String) fieldValue;
244 quark = getQuarkRelativeAndAdd(startQuark, fieldString);
245 } else if (fieldValue instanceof Long) {
246 Long fieldLong = (Long) fieldValue;
247 quark = getQuarkRelativeAndAdd(startQuark, fieldLong.toString());
248 } else if (fieldValue instanceof Integer) {
249 Integer fieldInterger = (Integer) fieldValue;
250 quark = getQuarkRelativeAndAdd(startQuark, fieldInterger.toString());
251 }
252 return quark;
253 }
254 case QUERY: {
255 int quark;
256 ITmfStateValue value = TmfStateValue.nullValue();
257 int quarkQuery = IXmlStateSystemContainer.ROOT_QUARK;
258
259 for (ITmfXmlStateAttribute attrib : fQueryList) {
260 quarkQuery = attrib.getAttributeQuark(event, quarkQuery, scenarioInfo);
261 if (quarkQuery == IXmlStateSystemContainer.ERROR_QUARK) {
262 break;
263 }
264 }
265
266 // the query may fail: for example CurrentThread if there
267 // has not been a sched_switch event
268 if (quarkQuery != IXmlStateSystemContainer.ERROR_QUARK) {
269 value = ss.queryOngoingState(quarkQuery);
270 }
271
272 switch (value.getType()) {
273 case INTEGER: {
274 int result = value.unboxInt();
275 quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result));
276 break;
277 }
278 case LONG: {
279 long result = value.unboxLong();
280 quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result));
281 break;
282 }
283 case STRING: {
284 String result = value.unboxStr();
285 quark = getQuarkRelativeAndAdd(startQuark, result);
286 break;
287 }
288 case DOUBLE:
289 case NULL:
290 case CUSTOM:
291 default:
292 quark = IXmlStateSystemContainer.ERROR_QUARK; // error
293 break;
294 }
295 return quark;
296 }
297 case LOCATION: {
298 int quark = startQuark;
299 String idLocation = name;
300
301 /* TODO: Add a fContainer.getLocation(id) method */
302 for (TmfXmlLocation location : fContainer.getLocations()) {
303 if (location.getId().equals(idLocation)) {
304 quark = location.getLocationQuark(event, quark, scenarioInfo);
305 if (quark == IXmlStateSystemContainer.ERROR_QUARK) {
306 break;
307 }
308 }
309 }
310 return quark;
311 }
312 case EVENTNAME: {
313 int quark = IXmlStateSystemContainer.ERROR_QUARK;
314 if (event == null) {
315 Activator.logWarning("XML State attribute: looking for an eventname, but event is null"); //$NON-NLS-1$
316 return quark;
317 }
318 quark = getQuarkRelativeAndAdd(startQuark, event.getName());
319 return quark;
320 }
321 case SELF:
322 return startQuark;
323 case NONE:
324 default:
325 return startQuark;
326 }
327 } catch (AttributeNotFoundException ae) {
328 /*
329 * This can be happen before the creation of the node for a query in
330 * the state system. Example : current thread before a sched_switch
331 */
332 return IXmlStateSystemContainer.ERROR_QUARK;
333 } catch (StateValueTypeException e) {
334 /*
335 * This would happen if we were trying to push/pop attributes not of
336 * type integer. Which, once again, should never happen.
337 */
338 Activator.logError("StateValueTypeException", e); //$NON-NLS-1$
339 return IXmlStateSystemContainer.ERROR_QUARK;
340 }
341 }
342
343 @Override
344 public String toString() {
345 return "TmfXmlStateAttribute " + fType + ": " + fName; //$NON-NLS-1$ //$NON-NLS-2$
346 }
347
348 }
This page took 0.038442 seconds and 4 git commands to generate.