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