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; |
0b563c20 JCK |
19 | import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; |
20 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; | |
21 | ||
2bdf0193 | 22 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator; |
e894a508 AM |
23 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
24 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; | |
25 | import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; | |
26 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; | |
27 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; | |
28 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; | |
2bdf0193 AM |
29 | import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer; |
30 | import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils; | |
31 | import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings; | |
32 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
33 | import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; | |
35f39420 AM |
34 | import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect; |
35 | import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; | |
0f7276b6 GB |
36 | import org.w3c.dom.Element; |
37 | ||
38 | /** | |
1d7e62f9 GB |
39 | * This Class implements a single attribute value in the XML-defined state |
40 | * system. | |
0f7276b6 GB |
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 | */ | |
1d7e62f9 | 54 | public abstract class TmfXmlStateAttribute implements ITmfXmlStateAttribute { |
0f7276b6 GB |
55 | |
56 | private enum StateAttributeType { | |
57 | NONE, | |
58 | CONSTANT, | |
59 | EVENTFIELD, | |
60 | QUERY, | |
1d7e62f9 | 61 | LOCATION, |
597168fc NE |
62 | SELF, |
63 | EVENTNAME | |
0f7276b6 GB |
64 | } |
65 | ||
0b563c20 JCK |
66 | private final String CURRENT_STATE = "#currentState"; //$NON-NLS-1$ |
67 | ||
3a5f73a1 JCK |
68 | private final String CURRENT_SCENARIO = "#CurrentScenario"; //$NON-NLS-1$ |
69 | ||
0f7276b6 GB |
70 | /** Type of attribute */ |
71 | private final StateAttributeType fType; | |
72 | ||
73 | /** Attribute's name */ | |
12685851 | 74 | private final @Nullable String fName; |
0f7276b6 GB |
75 | |
76 | /** List of attributes for a query */ | |
1d7e62f9 | 77 | private final List<ITmfXmlStateAttribute> fQueryList = new LinkedList<>(); |
0f7276b6 | 78 | |
1d7e62f9 | 79 | private final IXmlStateSystemContainer fContainer; |
0f7276b6 GB |
80 | |
81 | /** | |
82 | * Constructor | |
83 | * | |
1d7e62f9 GB |
84 | * @param modelFactory |
85 | * The factory used to create XML model elements | |
0f7276b6 GB |
86 | * @param attribute |
87 | * XML element of the attribute | |
1d7e62f9 GB |
88 | * @param container |
89 | * The state system container this state attribute belongs to | |
0f7276b6 | 90 | */ |
1d7e62f9 GB |
91 | protected TmfXmlStateAttribute(ITmfXmlModelFactory modelFactory, Element attribute, IXmlStateSystemContainer container) { |
92 | fContainer = container; | |
0f7276b6 GB |
93 | |
94 | switch (attribute.getAttribute(TmfXmlStrings.TYPE)) { | |
95 | case TmfXmlStrings.TYPE_CONSTANT: | |
96 | fType = StateAttributeType.CONSTANT; | |
266dc922 | 97 | fName = getAttributeName(attribute); |
0f7276b6 GB |
98 | break; |
99 | case TmfXmlStrings.EVENT_FIELD: | |
100 | fType = StateAttributeType.EVENTFIELD; | |
266dc922 | 101 | fName = getAttributeName(attribute); |
0f7276b6 GB |
102 | break; |
103 | case TmfXmlStrings.TYPE_LOCATION: | |
104 | fType = StateAttributeType.LOCATION; | |
266dc922 | 105 | fName = getAttributeName(attribute); |
0f7276b6 GB |
106 | break; |
107 | case TmfXmlStrings.TYPE_QUERY: | |
4c4e2816 | 108 | List<@Nullable Element> childElements = XmlUtils.getChildElements(attribute); |
0f7276b6 | 109 | for (Element subAttributeNode : childElements) { |
12685851 GB |
110 | if (subAttributeNode == null) { |
111 | continue; | |
112 | } | |
1d7e62f9 | 113 | ITmfXmlStateAttribute subAttribute = modelFactory.createStateAttribute(subAttributeNode, fContainer); |
0f7276b6 GB |
114 | fQueryList.add(subAttribute); |
115 | } | |
116 | fType = StateAttributeType.QUERY; | |
117 | fName = null; | |
118 | break; | |
597168fc NE |
119 | case TmfXmlStrings.TYPE_EVENT_NAME: |
120 | fType = StateAttributeType.EVENTNAME; | |
266dc922 | 121 | fName = getAttributeName(attribute); |
597168fc | 122 | break; |
0f7276b6 GB |
123 | case TmfXmlStrings.NULL: |
124 | fType = StateAttributeType.NONE; | |
125 | fName = null; | |
126 | break; | |
1d7e62f9 GB |
127 | case TmfXmlStrings.TYPE_SELF: |
128 | fType = StateAttributeType.SELF; | |
129 | fName = null; | |
130 | break; | |
0f7276b6 GB |
131 | default: |
132 | throw new IllegalArgumentException("TmfXmlStateAttribute constructor: The XML element is not of the right type"); //$NON-NLS-1$ | |
133 | } | |
134 | } | |
135 | ||
266dc922 MK |
136 | private String getAttributeName(Element attribute) { |
137 | return fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)).intern(); | |
138 | } | |
139 | ||
0f7276b6 | 140 | /** |
0b563c20 | 141 | * @since 2.0 |
1d7e62f9 GB |
142 | */ |
143 | @Override | |
0b563c20 JCK |
144 | public int getAttributeQuark(int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) { |
145 | return getAttributeQuark(null, startQuark, scenarioInfo); | |
1d7e62f9 GB |
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 | 190 | /** |
0b563c20 | 191 | * @since 2.0 |
1d7e62f9 GB |
192 | */ |
193 | @Override | |
0b563c20 | 194 | public int getAttributeQuark(@Nullable ITmfEvent event, int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) { |
1d7e62f9 | 195 | ITmfStateSystem ss = getStateSystem(); |
12685851 GB |
196 | if (ss == null) { |
197 | throw new IllegalStateException("The state system hasn't been initialized yet"); //$NON-NLS-1$ | |
198 | } | |
0b563c20 JCK |
199 | String name = nullToEmptyString(fName); |
200 | if (name.length() > 0 && name.charAt(0) == '#' && scenarioInfo == null) { | |
201 | throw new IllegalStateException("XML Attribute needs " + fName + " but the data is not available."); //$NON-NLS-1$//$NON-NLS-2$ | |
202 | } | |
3a5f73a1 JCK |
203 | name = name.equals(CURRENT_STATE) ? checkNotNull(scenarioInfo).getActiveState() |
204 | : fName; | |
0f7276b6 GB |
205 | |
206 | try { | |
207 | switch (fType) { | |
208 | case CONSTANT: { | |
209 | int quark; | |
0b563c20 JCK |
210 | if (name == null) { |
211 | throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$ | |
212 | } | |
3a5f73a1 JCK |
213 | if (name.equals(CURRENT_SCENARIO)) { |
214 | return checkNotNull(scenarioInfo).getQuark(); | |
215 | } | |
1d7e62f9 | 216 | if (startQuark == IXmlStateSystemContainer.ROOT_QUARK) { |
0b563c20 | 217 | quark = getQuarkAbsoluteAndAdd(name); |
0f7276b6 | 218 | } else { |
0b563c20 | 219 | quark = getQuarkRelativeAndAdd(startQuark, name); |
0f7276b6 GB |
220 | } |
221 | return quark; | |
222 | } | |
223 | case EVENTFIELD: { | |
1d7e62f9 GB |
224 | int quark = IXmlStateSystemContainer.ERROR_QUARK; |
225 | if (event == null) { | |
226 | Activator.logWarning("XML State attribute: looking for an event field, but event is null"); //$NON-NLS-1$ | |
227 | return quark; | |
228 | } | |
12685851 | 229 | if (name == null) { |
0b563c20 | 230 | throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$ |
12685851 GB |
231 | } |
232 | if (name.equals(TmfXmlStrings.CPU)) { | |
35f39420 | 233 | /* See if the event advertises a CPU aspect */ |
b3867ecc | 234 | Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent( |
b1aad44e | 235 | event.getTrace(), TmfCpuAspect.class, event); |
b3867ecc | 236 | if (cpu != null) { |
b1aad44e | 237 | quark = getQuarkRelativeAndAdd(startQuark, cpu.toString()); |
35f39420 AM |
238 | } |
239 | } else { | |
1d7e62f9 | 240 | final ITmfEventField content = event.getContent(); |
0f7276b6 | 241 | /* stop if the event field doesn't exist */ |
0b563c20 | 242 | if (content.getField(name) == null) { |
1d7e62f9 | 243 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
244 | } |
245 | ||
0b563c20 | 246 | Object field = content.getField(name).getValue(); |
0f7276b6 GB |
247 | |
248 | if (field instanceof String) { | |
249 | String fieldString = (String) field; | |
1d7e62f9 | 250 | quark = getQuarkRelativeAndAdd(startQuark, fieldString); |
0f7276b6 GB |
251 | } else if (field instanceof Long) { |
252 | Long fieldLong = (Long) field; | |
1d7e62f9 | 253 | quark = getQuarkRelativeAndAdd(startQuark, fieldLong.toString()); |
0f7276b6 GB |
254 | } else if (field instanceof Integer) { |
255 | Integer fieldInterger = (Integer) field; | |
1d7e62f9 | 256 | quark = getQuarkRelativeAndAdd(startQuark, fieldInterger.toString()); |
0f7276b6 | 257 | } |
35f39420 | 258 | } |
0f7276b6 GB |
259 | return quark; |
260 | } | |
261 | case QUERY: { | |
262 | int quark; | |
263 | ITmfStateValue value = TmfStateValue.nullValue(); | |
1d7e62f9 | 264 | int quarkQuery = IXmlStateSystemContainer.ROOT_QUARK; |
0f7276b6 | 265 | |
1d7e62f9 | 266 | for (ITmfXmlStateAttribute attrib : fQueryList) { |
0b563c20 | 267 | quarkQuery = attrib.getAttributeQuark(event, quarkQuery, scenarioInfo); |
1d7e62f9 | 268 | if (quarkQuery == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
269 | break; |
270 | } | |
271 | } | |
272 | ||
273 | // the query may fail: for example CurrentThread if there | |
274 | // has not been a sched_switch event | |
1d7e62f9 | 275 | if (quarkQuery != IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
276 | value = ss.queryOngoingState(quarkQuery); |
277 | } | |
278 | ||
279 | switch (value.getType()) { | |
280 | case INTEGER: { | |
281 | int result = value.unboxInt(); | |
1d7e62f9 | 282 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
283 | break; |
284 | } | |
285 | case LONG: { | |
286 | long result = value.unboxLong(); | |
1d7e62f9 | 287 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
288 | break; |
289 | } | |
290 | case STRING: { | |
291 | String result = value.unboxStr(); | |
1d7e62f9 | 292 | quark = getQuarkRelativeAndAdd(startQuark, result); |
0f7276b6 GB |
293 | break; |
294 | } | |
295 | case DOUBLE: | |
296 | case NULL: | |
297 | default: | |
1d7e62f9 | 298 | quark = IXmlStateSystemContainer.ERROR_QUARK; // error |
0f7276b6 GB |
299 | break; |
300 | } | |
301 | return quark; | |
302 | } | |
303 | case LOCATION: { | |
304 | int quark = startQuark; | |
0b563c20 | 305 | String idLocation = name; |
0f7276b6 | 306 | |
1d7e62f9 GB |
307 | /* TODO: Add a fContainer.getLocation(id) method */ |
308 | for (TmfXmlLocation location : fContainer.getLocations()) { | |
0f7276b6 | 309 | if (location.getId().equals(idLocation)) { |
0b563c20 | 310 | quark = location.getLocationQuark(event, quark, scenarioInfo); |
1d7e62f9 | 311 | if (quark == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
312 | break; |
313 | } | |
314 | } | |
315 | } | |
316 | return quark; | |
317 | } | |
597168fc NE |
318 | case EVENTNAME: { |
319 | int quark = IXmlStateSystemContainer.ERROR_QUARK; | |
320 | if (event == null) { | |
321 | Activator.logWarning("XML State attribute: looking for an eventname, but event is null"); //$NON-NLS-1$ | |
322 | return quark; | |
323 | } | |
578716e6 | 324 | quark = getQuarkRelativeAndAdd(startQuark, event.getName()); |
597168fc NE |
325 | return quark; |
326 | } | |
1d7e62f9 GB |
327 | case SELF: |
328 | return startQuark; | |
0f7276b6 GB |
329 | case NONE: |
330 | default: | |
331 | return startQuark; | |
332 | } | |
333 | } catch (AttributeNotFoundException ae) { | |
334 | /* | |
335 | * This can be happen before the creation of the node for a query in | |
336 | * the state system. Example : current thread before a sched_switch | |
337 | */ | |
1d7e62f9 | 338 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
339 | } catch (StateValueTypeException e) { |
340 | /* | |
341 | * This would happen if we were trying to push/pop attributes not of | |
342 | * type integer. Which, once again, should never happen. | |
343 | */ | |
344 | Activator.logError("StateValueTypeException", e); //$NON-NLS-1$ | |
1d7e62f9 | 345 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
346 | } |
347 | } | |
348 | ||
446598f9 GB |
349 | @Override |
350 | public String toString() { | |
351 | return "TmfXmlStateAttribute " + fType + ": " + fName; //$NON-NLS-1$ //$NON-NLS-2$ | |
352 | } | |
353 | ||
52293ccd | 354 | } |