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