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 SCENARIO_NAME = "#scenarioName"; //$NON-NLS-1$ |
67 | ||
68 | private final String CURRENT_STATE = "#currentState"; //$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; | |
1d7e62f9 | 97 | fName = fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)); |
0f7276b6 GB |
98 | break; |
99 | case TmfXmlStrings.EVENT_FIELD: | |
100 | fType = StateAttributeType.EVENTFIELD; | |
1d7e62f9 | 101 | fName = fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)); |
0f7276b6 GB |
102 | break; |
103 | case TmfXmlStrings.TYPE_LOCATION: | |
104 | fType = StateAttributeType.LOCATION; | |
1d7e62f9 | 105 | fName = fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)); |
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; | |
121 | fName = fContainer.getAttributeValue(attribute.getAttribute(TmfXmlStrings.VALUE)); | |
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 | ||
136 | /** | |
0b563c20 | 137 | * @since 2.0 |
1d7e62f9 GB |
138 | */ |
139 | @Override | |
0b563c20 JCK |
140 | public int getAttributeQuark(int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) { |
141 | return getAttributeQuark(null, startQuark, scenarioInfo); | |
1d7e62f9 GB |
142 | } |
143 | ||
144 | /** | |
145 | * Basic quark-retrieving method. Pass an attribute in parameter as an array | |
146 | * of strings, the matching quark will be returned. If the attribute does | |
147 | * not exist, it will add the quark to the state system if the context | |
148 | * allows it. | |
149 | * | |
150 | * See {@link ITmfStateSystemBuilder#getQuarkAbsoluteAndAdd(String...)} | |
151 | * | |
152 | * @param path | |
153 | * Full path to the attribute | |
154 | * @return The quark for this attribute | |
155 | * @throws AttributeNotFoundException | |
156 | * The attribute does not exist and cannot be added | |
157 | */ | |
158 | protected abstract int getQuarkAbsoluteAndAdd(String... path) throws AttributeNotFoundException; | |
159 | ||
160 | /** | |
161 | * Quark-retrieving method, but the attribute is queried starting from the | |
162 | * startNodeQuark. If the attribute does not exist, it will add it to the | |
163 | * state system if the context allows it. | |
164 | * | |
165 | * See {@link ITmfStateSystemBuilder#getQuarkRelativeAndAdd(int, String...)} | |
166 | * | |
167 | * @param startNodeQuark | |
168 | * The quark of the attribute from which 'path' originates. | |
169 | * @param path | |
170 | * Relative path to the attribute | |
171 | * @return The quark for this attribute | |
172 | * @throws AttributeNotFoundException | |
173 | * The attribute does not exist and cannot be added | |
174 | */ | |
175 | protected abstract int getQuarkRelativeAndAdd(int startNodeQuark, String... path) throws AttributeNotFoundException; | |
176 | ||
177 | /** | |
178 | * Get the state system associated with this attribute's container | |
179 | * | |
180 | * @return The state system associated with this state attribute | |
0f7276b6 | 181 | */ |
12685851 | 182 | protected @Nullable ITmfStateSystem getStateSystem() { |
1d7e62f9 GB |
183 | return fContainer.getStateSystem(); |
184 | } | |
0f7276b6 | 185 | |
1d7e62f9 | 186 | /** |
0b563c20 | 187 | * @since 2.0 |
1d7e62f9 GB |
188 | */ |
189 | @Override | |
0b563c20 | 190 | public int getAttributeQuark(@Nullable ITmfEvent event, int startQuark, @Nullable TmfXmlScenarioInfo scenarioInfo) { |
1d7e62f9 | 191 | ITmfStateSystem ss = getStateSystem(); |
12685851 GB |
192 | if (ss == null) { |
193 | throw new IllegalStateException("The state system hasn't been initialized yet"); //$NON-NLS-1$ | |
194 | } | |
0b563c20 JCK |
195 | String name = nullToEmptyString(fName); |
196 | if (name.length() > 0 && name.charAt(0) == '#' && scenarioInfo == null) { | |
197 | throw new IllegalStateException("XML Attribute needs " + fName + " but the data is not available."); //$NON-NLS-1$//$NON-NLS-2$ | |
198 | } | |
199 | name = name.equals(SCENARIO_NAME) ? checkNotNull(scenarioInfo).getScenarioName() : name.equals(CURRENT_STATE) ? checkNotNull(scenarioInfo).getActiveState() : fName; | |
0f7276b6 GB |
200 | |
201 | try { | |
202 | switch (fType) { | |
203 | case CONSTANT: { | |
204 | int quark; | |
0b563c20 JCK |
205 | if (name == null) { |
206 | throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$ | |
207 | } | |
1d7e62f9 | 208 | if (startQuark == IXmlStateSystemContainer.ROOT_QUARK) { |
0b563c20 | 209 | quark = getQuarkAbsoluteAndAdd(name); |
0f7276b6 | 210 | } else { |
0b563c20 | 211 | quark = getQuarkRelativeAndAdd(startQuark, name); |
0f7276b6 GB |
212 | } |
213 | return quark; | |
214 | } | |
215 | case EVENTFIELD: { | |
1d7e62f9 GB |
216 | int quark = IXmlStateSystemContainer.ERROR_QUARK; |
217 | if (event == null) { | |
218 | Activator.logWarning("XML State attribute: looking for an event field, but event is null"); //$NON-NLS-1$ | |
219 | return quark; | |
220 | } | |
12685851 | 221 | if (name == null) { |
0b563c20 | 222 | throw new IllegalStateException("Invalid attribute name"); //$NON-NLS-1$ |
12685851 GB |
223 | } |
224 | if (name.equals(TmfXmlStrings.CPU)) { | |
35f39420 | 225 | /* See if the event advertises a CPU aspect */ |
b3867ecc | 226 | Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent( |
b1aad44e | 227 | event.getTrace(), TmfCpuAspect.class, event); |
b3867ecc | 228 | if (cpu != null) { |
b1aad44e | 229 | quark = getQuarkRelativeAndAdd(startQuark, cpu.toString()); |
35f39420 AM |
230 | } |
231 | } else { | |
1d7e62f9 | 232 | final ITmfEventField content = event.getContent(); |
0f7276b6 | 233 | /* stop if the event field doesn't exist */ |
0b563c20 | 234 | if (content.getField(name) == null) { |
1d7e62f9 | 235 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
236 | } |
237 | ||
0b563c20 | 238 | Object field = content.getField(name).getValue(); |
0f7276b6 GB |
239 | |
240 | if (field instanceof String) { | |
241 | String fieldString = (String) field; | |
1d7e62f9 | 242 | quark = getQuarkRelativeAndAdd(startQuark, fieldString); |
0f7276b6 GB |
243 | } else if (field instanceof Long) { |
244 | Long fieldLong = (Long) field; | |
1d7e62f9 | 245 | quark = getQuarkRelativeAndAdd(startQuark, fieldLong.toString()); |
0f7276b6 GB |
246 | } else if (field instanceof Integer) { |
247 | Integer fieldInterger = (Integer) field; | |
1d7e62f9 | 248 | quark = getQuarkRelativeAndAdd(startQuark, fieldInterger.toString()); |
0f7276b6 | 249 | } |
35f39420 | 250 | } |
0f7276b6 GB |
251 | return quark; |
252 | } | |
253 | case QUERY: { | |
254 | int quark; | |
255 | ITmfStateValue value = TmfStateValue.nullValue(); | |
1d7e62f9 | 256 | int quarkQuery = IXmlStateSystemContainer.ROOT_QUARK; |
0f7276b6 | 257 | |
1d7e62f9 | 258 | for (ITmfXmlStateAttribute attrib : fQueryList) { |
0b563c20 | 259 | quarkQuery = attrib.getAttributeQuark(event, quarkQuery, scenarioInfo); |
1d7e62f9 | 260 | if (quarkQuery == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
261 | break; |
262 | } | |
263 | } | |
264 | ||
265 | // the query may fail: for example CurrentThread if there | |
266 | // has not been a sched_switch event | |
1d7e62f9 | 267 | if (quarkQuery != IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
268 | value = ss.queryOngoingState(quarkQuery); |
269 | } | |
270 | ||
271 | switch (value.getType()) { | |
272 | case INTEGER: { | |
273 | int result = value.unboxInt(); | |
1d7e62f9 | 274 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
275 | break; |
276 | } | |
277 | case LONG: { | |
278 | long result = value.unboxLong(); | |
1d7e62f9 | 279 | quark = getQuarkRelativeAndAdd(startQuark, String.valueOf(result)); |
0f7276b6 GB |
280 | break; |
281 | } | |
282 | case STRING: { | |
283 | String result = value.unboxStr(); | |
1d7e62f9 | 284 | quark = getQuarkRelativeAndAdd(startQuark, result); |
0f7276b6 GB |
285 | break; |
286 | } | |
287 | case DOUBLE: | |
288 | case NULL: | |
289 | default: | |
1d7e62f9 | 290 | quark = IXmlStateSystemContainer.ERROR_QUARK; // error |
0f7276b6 GB |
291 | break; |
292 | } | |
293 | return quark; | |
294 | } | |
295 | case LOCATION: { | |
296 | int quark = startQuark; | |
0b563c20 | 297 | String idLocation = name; |
0f7276b6 | 298 | |
1d7e62f9 GB |
299 | /* TODO: Add a fContainer.getLocation(id) method */ |
300 | for (TmfXmlLocation location : fContainer.getLocations()) { | |
0f7276b6 | 301 | if (location.getId().equals(idLocation)) { |
0b563c20 | 302 | quark = location.getLocationQuark(event, quark, scenarioInfo); |
1d7e62f9 | 303 | if (quark == IXmlStateSystemContainer.ERROR_QUARK) { |
0f7276b6 GB |
304 | break; |
305 | } | |
306 | } | |
307 | } | |
308 | return quark; | |
309 | } | |
597168fc NE |
310 | case EVENTNAME: { |
311 | int quark = IXmlStateSystemContainer.ERROR_QUARK; | |
312 | if (event == null) { | |
313 | Activator.logWarning("XML State attribute: looking for an eventname, but event is null"); //$NON-NLS-1$ | |
314 | return quark; | |
315 | } | |
578716e6 | 316 | quark = getQuarkRelativeAndAdd(startQuark, event.getName()); |
597168fc NE |
317 | return quark; |
318 | } | |
1d7e62f9 GB |
319 | case SELF: |
320 | return startQuark; | |
0f7276b6 GB |
321 | case NONE: |
322 | default: | |
323 | return startQuark; | |
324 | } | |
325 | } catch (AttributeNotFoundException ae) { | |
326 | /* | |
327 | * This can be happen before the creation of the node for a query in | |
328 | * the state system. Example : current thread before a sched_switch | |
329 | */ | |
1d7e62f9 | 330 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
331 | } catch (StateValueTypeException e) { |
332 | /* | |
333 | * This would happen if we were trying to push/pop attributes not of | |
334 | * type integer. Which, once again, should never happen. | |
335 | */ | |
336 | Activator.logError("StateValueTypeException", e); //$NON-NLS-1$ | |
1d7e62f9 | 337 | return IXmlStateSystemContainer.ERROR_QUARK; |
0f7276b6 GB |
338 | } |
339 | } | |
340 | ||
446598f9 GB |
341 | @Override |
342 | public String toString() { | |
343 | return "TmfXmlStateAttribute " + fType + ": " + fName; //$NON-NLS-1$ //$NON-NLS-2$ | |
344 | } | |
345 | ||
52293ccd | 346 | } |