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