Commit | Line | Data |
---|---|---|
0f7276b6 | 1 | /******************************************************************************* |
ed902a2b | 2 | * Copyright (c) 2014, 2015 Ecole Polytechnique de Montreal |
0f7276b6 GB |
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: | |
4c4e2816 | 101 | List<@Nullable Element> childElements = XmlUtils.getChildElements(attribute); |
0f7276b6 | 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 | 237 | /* See if the event advertises a CPU aspect */ |
b1aad44e GB |
238 | Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent( |
239 | event.getTrace(), TmfCpuAspect.class, event); | |
240 | if (cpuObj != null) { | |
241 | Integer cpu = (Integer) cpuObj; | |
242 | quark = getQuarkRelativeAndAdd(startQuark, cpu.toString()); | |
35f39420 AM |
243 | } |
244 | } else { | |
1d7e62f9 | 245 | final ITmfEventField content = event.getContent(); |
0f7276b6 GB |
246 | /* stop if the event field doesn't exist */ |
247 | if (content.getField(fName) == null) { | |
1d7e62f9 | 248 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
249 | } |
250 | ||
251 | Object field = content.getField(fName).getValue(); | |
252 | ||
253 | if (field instanceof String) { | |
254 | String fieldString = (String) field; | |
1d7e62f9 | 255 | quark = getQuarkRelativeAndAdd(startQuark, fieldString); |
0f7276b6 GB |
256 | } else if (field instanceof Long) { |
257 | Long fieldLong = (Long) field; | |
1d7e62f9 | 258 | quark = getQuarkRelativeAndAdd(startQuark, fieldLong.toString()); |
0f7276b6 GB |
259 | } else if (field instanceof Integer) { |
260 | Integer fieldInterger = (Integer) field; | |
1d7e62f9 | 261 | quark = getQuarkRelativeAndAdd(startQuark, fieldInterger.toString()); |
0f7276b6 | 262 | } |
35f39420 | 263 | } |
0f7276b6 GB |
264 | return quark; |
265 | } | |
266 | case QUERY: { | |
267 | int quark; | |
268 | ITmfStateValue value = TmfStateValue.nullValue(); | |
1d7e62f9 | 269 | int quarkQuery = IXmlStateSystemContainer.ROOT_QUARK; |
0f7276b6 | 270 | |
1d7e62f9 | 271 | for (ITmfXmlStateAttribute attrib : fQueryList) { |
0f7276b6 | 272 | quarkQuery = attrib.getAttributeQuark(event, quarkQuery); |
1d7e62f9 | 273 | if (quarkQuery == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
274 | break; |
275 | } | |
276 | } | |
277 | ||
278 | // the query may fail: for example CurrentThread if there | |
279 | // has not been a sched_switch event | |
1d7e62f9 | 280 | if (quarkQuery != IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
281 | value = ss.queryOngoingState(quarkQuery); |
282 | } | |
283 | ||
284 | switch (value.getType()) { | |
285 | case INTEGER: { | |
286 | int result = value.unboxInt(); | |
1d7e62f9 | 287 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
288 | break; |
289 | } | |
290 | case LONG: { | |
291 | long result = value.unboxLong(); | |
1d7e62f9 | 292 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
293 | break; |
294 | } | |
295 | case STRING: { | |
296 | String result = value.unboxStr(); | |
1d7e62f9 | 297 | quark = getQuarkRelativeAndAdd(startQuark, result); |
0f7276b6 GB |
298 | break; |
299 | } | |
300 | case DOUBLE: | |
301 | case NULL: | |
302 | default: | |
1d7e62f9 | 303 | quark = IXmlStateSystemContainer.ERROR_QUARK; // error |
0f7276b6 GB |
304 | break; |
305 | } | |
306 | return quark; | |
307 | } | |
308 | case LOCATION: { | |
309 | int quark = startQuark; | |
310 | String idLocation = fName; | |
311 | ||
1d7e62f9 GB |
312 | /* TODO: Add a fContainer.getLocation(id) method */ |
313 | for (TmfXmlLocation location : fContainer.getLocations()) { | |
0f7276b6 GB |
314 | if (location.getId().equals(idLocation)) { |
315 | quark = location.getLocationQuark(event, quark); | |
1d7e62f9 | 316 | if (quark == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
317 | break; |
318 | } | |
319 | } | |
320 | } | |
321 | return quark; | |
322 | } | |
597168fc NE |
323 | case EVENTNAME: { |
324 | int quark = IXmlStateSystemContainer.ERROR_QUARK; | |
325 | if (event == null) { | |
326 | Activator.logWarning("XML State attribute: looking for an eventname, but event is null"); //$NON-NLS-1$ | |
327 | return quark; | |
328 | } | |
578716e6 | 329 | quark = getQuarkRelativeAndAdd(startQuark, event.getName()); |
597168fc NE |
330 | return quark; |
331 | } | |
1d7e62f9 GB |
332 | case SELF: |
333 | return startQuark; | |
0f7276b6 GB |
334 | case NONE: |
335 | default: | |
336 | return startQuark; | |
337 | } | |
338 | } catch (AttributeNotFoundException ae) { | |
339 | /* | |
340 | * This can be happen before the creation of the node for a query in | |
341 | * the state system. Example : current thread before a sched_switch | |
342 | */ | |
1d7e62f9 | 343 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
344 | } catch (StateValueTypeException e) { |
345 | /* | |
346 | * This would happen if we were trying to push/pop attributes not of | |
347 | * type integer. Which, once again, should never happen. | |
348 | */ | |
349 | Activator.logError("StateValueTypeException", e); //$NON-NLS-1$ | |
1d7e62f9 | 350 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
351 | } |
352 | } | |
353 | ||
446598f9 GB |
354 | @Override |
355 | public String toString() { | |
356 | return "TmfXmlStateAttribute " + fType + ": " + fName; //$NON-NLS-1$ //$NON-NLS-2$ | |
357 | } | |
358 | ||
52293ccd | 359 | } |